|
|
@ -1,15 +1,17 @@
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $
|
|
|
|
** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $
|
|
|
|
** Lua Parser
|
|
|
|
** Lua Parser
|
|
|
|
** See Copyright Notice in lua.h
|
|
|
|
** See Copyright Notice in lua.h
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define lparser_c
|
|
|
|
#define lparser_c
|
|
|
|
#define LUA_CORE
|
|
|
|
#define LUA_CORE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lprefix.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "lua.h"
|
|
|
|
#include "lua.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "lcode.h"
|
|
|
|
#include "lcode.h"
|
|
|
@ -35,17 +37,21 @@
|
|
|
|
#define hasmultret(k) ((k) == VCALL || (k) == VVARARG)
|
|
|
|
#define hasmultret(k) ((k) == VCALL || (k) == VVARARG)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* because all strings are unified by the scanner, the parser
|
|
|
|
|
|
|
|
can use pointer equality for string equality */
|
|
|
|
|
|
|
|
#define eqstr(a,b) ((a) == (b))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
** nodes for block list (list of active blocks)
|
|
|
|
** nodes for block list (list of active blocks)
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
typedef struct BlockCnt {
|
|
|
|
typedef struct BlockCnt {
|
|
|
|
struct BlockCnt *previous; /* chain */
|
|
|
|
struct BlockCnt *previous; /* chain */
|
|
|
|
short firstlabel; /* index of first label in this block */
|
|
|
|
int firstlabel; /* index of first label in this block */
|
|
|
|
short firstgoto; /* index of first pending goto in this block */
|
|
|
|
int firstgoto; /* index of first pending goto in this block */
|
|
|
|
lu_byte nactvar; /* # active locals outside the block */
|
|
|
|
lu_byte nactvar; /* # active locals outside the block */
|
|
|
|
lu_byte upval; /* true if some variable in the block is an upvalue */
|
|
|
|
lu_byte upval; /* true if some variable in the block is an upvalue */
|
|
|
|
lu_byte isloop; /* true if `block' is a loop */
|
|
|
|
lu_byte isloop; /* true if 'block' is a loop */
|
|
|
|
} BlockCnt;
|
|
|
|
} BlockCnt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -57,19 +63,9 @@ static void statement (LexState *ls);
|
|
|
|
static void expr (LexState *ls, expdesc *v);
|
|
|
|
static void expr (LexState *ls, expdesc *v);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void anchor_token (LexState *ls) {
|
|
|
|
|
|
|
|
/* last token from outer function must be EOS */
|
|
|
|
|
|
|
|
lua_assert(ls->fs != NULL || ls->t.token == TK_EOS);
|
|
|
|
|
|
|
|
if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) {
|
|
|
|
|
|
|
|
TString *ts = ls->t.seminfo.ts;
|
|
|
|
|
|
|
|
luaX_newstring(ls, getstr(ts), ts->tsv.len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* semantic error */
|
|
|
|
/* semantic error */
|
|
|
|
static l_noret semerror (LexState *ls, const char *msg) {
|
|
|
|
static l_noret semerror (LexState *ls, const char *msg) {
|
|
|
|
ls->t.token = 0; /* remove 'near to' from final message */
|
|
|
|
ls->t.token = 0; /* remove "near <token>" from final message */
|
|
|
|
luaX_syntaxerror(ls, msg);
|
|
|
|
luaX_syntaxerror(ls, msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -168,7 +164,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
|
|
|
|
int oldsize = f->sizelocvars;
|
|
|
|
int oldsize = f->sizelocvars;
|
|
|
|
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
|
|
|
|
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
|
|
|
|
LocVar, SHRT_MAX, "local variables");
|
|
|
|
LocVar, SHRT_MAX, "local variables");
|
|
|
|
while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
|
|
|
|
while (oldsize < f->sizelocvars)
|
|
|
|
|
|
|
|
f->locvars[oldsize++].varname = NULL;
|
|
|
|
f->locvars[fs->nlocvars].varname = varname;
|
|
|
|
f->locvars[fs->nlocvars].varname = varname;
|
|
|
|
luaC_objbarrier(ls->L, f, varname);
|
|
|
|
luaC_objbarrier(ls->L, f, varname);
|
|
|
|
return fs->nlocvars++;
|
|
|
|
return fs->nlocvars++;
|
|
|
@ -222,7 +219,7 @@ static int searchupvalue (FuncState *fs, TString *name) {
|
|
|
|
int i;
|
|
|
|
int i;
|
|
|
|
Upvaldesc *up = fs->f->upvalues;
|
|
|
|
Upvaldesc *up = fs->f->upvalues;
|
|
|
|
for (i = 0; i < fs->nups; i++) {
|
|
|
|
for (i = 0; i < fs->nups; i++) {
|
|
|
|
if (luaS_eqstr(up[i].name, name)) return i;
|
|
|
|
if (eqstr(up[i].name, name)) return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1; /* not found */
|
|
|
|
return -1; /* not found */
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -234,7 +231,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
|
|
|
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
|
|
|
|
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
|
|
|
|
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
|
|
|
|
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
|
|
|
|
Upvaldesc, MAXUPVAL, "upvalues");
|
|
|
|
Upvaldesc, MAXUPVAL, "upvalues");
|
|
|
|
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
|
|
|
|
while (oldsize < f->sizeupvalues)
|
|
|
|
|
|
|
|
f->upvalues[oldsize++].name = NULL;
|
|
|
|
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
|
|
|
|
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
|
|
|
|
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
|
|
|
|
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
|
|
|
|
f->upvalues[fs->nups].name = name;
|
|
|
|
f->upvalues[fs->nups].name = name;
|
|
|
@ -246,7 +244,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
|
|
|
static int searchvar (FuncState *fs, TString *n) {
|
|
|
|
static int searchvar (FuncState *fs, TString *n) {
|
|
|
|
int i;
|
|
|
|
int i;
|
|
|
|
for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
|
|
|
|
for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
|
|
|
|
if (luaS_eqstr(n, getlocvar(fs, i)->varname))
|
|
|
|
if (eqstr(n, getlocvar(fs, i)->varname))
|
|
|
|
return i;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1; /* not found */
|
|
|
|
return -1; /* not found */
|
|
|
@ -259,7 +257,8 @@ static int searchvar (FuncState *fs, TString *n) {
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static void markupval (FuncState *fs, int level) {
|
|
|
|
static void markupval (FuncState *fs, int level) {
|
|
|
|
BlockCnt *bl = fs->bl;
|
|
|
|
BlockCnt *bl = fs->bl;
|
|
|
|
while (bl->nactvar > level) bl = bl->previous;
|
|
|
|
while (bl->nactvar > level)
|
|
|
|
|
|
|
|
bl = bl->previous;
|
|
|
|
bl->upval = 1;
|
|
|
|
bl->upval = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -268,27 +267,26 @@ static void markupval (FuncState *fs, int level) {
|
|
|
|
Find variable with given name 'n'. If it is an upvalue, add this
|
|
|
|
Find variable with given name 'n'. If it is an upvalue, add this
|
|
|
|
upvalue into all intermediate functions.
|
|
|
|
upvalue into all intermediate functions.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
|
|
|
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
|
|
|
if (fs == NULL) /* no more levels? */
|
|
|
|
if (fs == NULL) /* no more levels? */
|
|
|
|
return VVOID; /* default is global */
|
|
|
|
init_exp(var, VVOID, 0); /* default is global */
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
int v = searchvar(fs, n); /* look up locals at current level */
|
|
|
|
int v = searchvar(fs, n); /* look up locals at current level */
|
|
|
|
if (v >= 0) { /* found? */
|
|
|
|
if (v >= 0) { /* found? */
|
|
|
|
init_exp(var, VLOCAL, v); /* variable is local */
|
|
|
|
init_exp(var, VLOCAL, v); /* variable is local */
|
|
|
|
if (!base)
|
|
|
|
if (!base)
|
|
|
|
markupval(fs, v); /* local will be used as an upval */
|
|
|
|
markupval(fs, v); /* local will be used as an upval */
|
|
|
|
return VLOCAL;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* not found as local at current level; try upvalues */
|
|
|
|
else { /* not found as local at current level; try upvalues */
|
|
|
|
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
|
|
|
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
|
|
|
if (idx < 0) { /* not found? */
|
|
|
|
if (idx < 0) { /* not found? */
|
|
|
|
if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
|
|
|
|
singlevaraux(fs->prev, n, var, 0); /* try upper levels */
|
|
|
|
return VVOID; /* not found; is a global */
|
|
|
|
if (var->k == VVOID) /* not found? */
|
|
|
|
|
|
|
|
return; /* it is a global */
|
|
|
|
/* else was LOCAL or UPVAL */
|
|
|
|
/* else was LOCAL or UPVAL */
|
|
|
|
idx = newupvalue(fs, n, var); /* will be a new upvalue */
|
|
|
|
idx = newupvalue(fs, n, var); /* will be a new upvalue */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
init_exp(var, VUPVAL, idx);
|
|
|
|
init_exp(var, VUPVAL, idx); /* new or old upvalue */
|
|
|
|
return VUPVAL;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -297,10 +295,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
|
|
|
static void singlevar (LexState *ls, expdesc *var) {
|
|
|
|
static void singlevar (LexState *ls, expdesc *var) {
|
|
|
|
TString *varname = str_checkname(ls);
|
|
|
|
TString *varname = str_checkname(ls);
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
|
|
|
|
singlevaraux(fs, varname, var, 1);
|
|
|
|
|
|
|
|
if (var->k == VVOID) { /* global name? */
|
|
|
|
expdesc key;
|
|
|
|
expdesc key;
|
|
|
|
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
|
|
|
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
|
|
|
lua_assert(var->k == VLOCAL || var->k == VUPVAL);
|
|
|
|
lua_assert(var->k != VVOID); /* this one must exist */
|
|
|
|
codestring(ls, &key, varname); /* key is variable name */
|
|
|
|
codestring(ls, &key, varname); /* key is variable name */
|
|
|
|
luaK_indexed(fs, var, &key); /* env[varname] */
|
|
|
|
luaK_indexed(fs, var, &key); /* env[varname] */
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -342,11 +341,11 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
Labellist *gl = &ls->dyd->gt;
|
|
|
|
Labellist *gl = &ls->dyd->gt;
|
|
|
|
Labeldesc *gt = &gl->arr[g];
|
|
|
|
Labeldesc *gt = &gl->arr[g];
|
|
|
|
lua_assert(luaS_eqstr(gt->name, label->name));
|
|
|
|
lua_assert(eqstr(gt->name, label->name));
|
|
|
|
if (gt->nactvar < label->nactvar) {
|
|
|
|
if (gt->nactvar < label->nactvar) {
|
|
|
|
TString *vname = getlocvar(fs, gt->nactvar)->varname;
|
|
|
|
TString *vname = getlocvar(fs, gt->nactvar)->varname;
|
|
|
|
const char *msg = luaO_pushfstring(ls->L,
|
|
|
|
const char *msg = luaO_pushfstring(ls->L,
|
|
|
|
"<goto %s> at line %d jumps into the scope of local " LUA_QS,
|
|
|
|
"<goto %s> at line %d jumps into the scope of local '%s'",
|
|
|
|
getstr(gt->name), gt->line, getstr(vname));
|
|
|
|
getstr(gt->name), gt->line, getstr(vname));
|
|
|
|
semerror(ls, msg);
|
|
|
|
semerror(ls, msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -369,7 +368,7 @@ static int findlabel (LexState *ls, int g) {
|
|
|
|
/* check labels in current block for a match */
|
|
|
|
/* check labels in current block for a match */
|
|
|
|
for (i = bl->firstlabel; i < dyd->label.n; i++) {
|
|
|
|
for (i = bl->firstlabel; i < dyd->label.n; i++) {
|
|
|
|
Labeldesc *lb = &dyd->label.arr[i];
|
|
|
|
Labeldesc *lb = &dyd->label.arr[i];
|
|
|
|
if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */
|
|
|
|
if (eqstr(lb->name, gt->name)) { /* correct label? */
|
|
|
|
if (gt->nactvar > lb->nactvar &&
|
|
|
|
if (gt->nactvar > lb->nactvar &&
|
|
|
|
(bl->upval || dyd->label.n > bl->firstlabel))
|
|
|
|
(bl->upval || dyd->label.n > bl->firstlabel))
|
|
|
|
luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
|
|
|
|
luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
|
|
|
@ -390,7 +389,7 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name,
|
|
|
|
l->arr[n].line = line;
|
|
|
|
l->arr[n].line = line;
|
|
|
|
l->arr[n].nactvar = ls->fs->nactvar;
|
|
|
|
l->arr[n].nactvar = ls->fs->nactvar;
|
|
|
|
l->arr[n].pc = pc;
|
|
|
|
l->arr[n].pc = pc;
|
|
|
|
l->n++;
|
|
|
|
l->n = n + 1;
|
|
|
|
return n;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -403,7 +402,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) {
|
|
|
|
Labellist *gl = &ls->dyd->gt;
|
|
|
|
Labellist *gl = &ls->dyd->gt;
|
|
|
|
int i = ls->fs->bl->firstgoto;
|
|
|
|
int i = ls->fs->bl->firstgoto;
|
|
|
|
while (i < gl->n) {
|
|
|
|
while (i < gl->n) {
|
|
|
|
if (luaS_eqstr(gl->arr[i].name, lb->name))
|
|
|
|
if (eqstr(gl->arr[i].name, lb->name))
|
|
|
|
closegoto(ls, i, lb);
|
|
|
|
closegoto(ls, i, lb);
|
|
|
|
else
|
|
|
|
else
|
|
|
|
i++;
|
|
|
|
i++;
|
|
|
@ -412,7 +411,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
** "export" pending gotos to outer level, to check them against
|
|
|
|
** export pending gotos to outer level, to check them against
|
|
|
|
** outer labels; if the block being exited has upvalues, and
|
|
|
|
** outer labels; if the block being exited has upvalues, and
|
|
|
|
** the goto exits the scope of any variable (which can be the
|
|
|
|
** the goto exits the scope of any variable (which can be the
|
|
|
|
** upvalue), close those variables being exited.
|
|
|
|
** upvalue), close those variables being exited.
|
|
|
@ -448,7 +447,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
** create a label named "break" to resolve break statements
|
|
|
|
** create a label named 'break' to resolve break statements
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static void breaklabel (LexState *ls) {
|
|
|
|
static void breaklabel (LexState *ls) {
|
|
|
|
TString *n = luaS_new(ls->L, "break");
|
|
|
|
TString *n = luaS_new(ls->L, "break");
|
|
|
@ -463,7 +462,7 @@ static void breaklabel (LexState *ls) {
|
|
|
|
static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
|
|
|
|
static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
|
|
|
|
const char *msg = isreserved(gt->name)
|
|
|
|
const char *msg = isreserved(gt->name)
|
|
|
|
? "<%s> at line %d not inside a loop"
|
|
|
|
? "<%s> at line %d not inside a loop"
|
|
|
|
: "no visible label " LUA_QS " for <goto> at line %d";
|
|
|
|
: "no visible label '%s' for <goto> at line %d";
|
|
|
|
msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
|
|
|
|
msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
|
|
|
|
semerror(ls, msg);
|
|
|
|
semerror(ls, msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -503,7 +502,8 @@ static Proto *addprototype (LexState *ls) {
|
|
|
|
if (fs->np >= f->sizep) {
|
|
|
|
if (fs->np >= f->sizep) {
|
|
|
|
int oldsize = f->sizep;
|
|
|
|
int oldsize = f->sizep;
|
|
|
|
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
|
|
|
|
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
|
|
|
|
while (oldsize < f->sizep) f->p[oldsize++] = NULL;
|
|
|
|
while (oldsize < f->sizep)
|
|
|
|
|
|
|
|
f->p[oldsize++] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f->p[fs->np++] = clp = luaF_newproto(L);
|
|
|
|
f->p[fs->np++] = clp = luaF_newproto(L);
|
|
|
|
luaC_objbarrier(L, f, clp);
|
|
|
|
luaC_objbarrier(L, f, clp);
|
|
|
@ -525,7 +525,6 @@ static void codeclosure (LexState *ls, expdesc *v) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
|
|
|
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
|
|
|
lua_State *L = ls->L;
|
|
|
|
|
|
|
|
Proto *f;
|
|
|
|
Proto *f;
|
|
|
|
fs->prev = ls->fs; /* linked list of funcstates */
|
|
|
|
fs->prev = ls->fs; /* linked list of funcstates */
|
|
|
|
fs->ls = ls;
|
|
|
|
fs->ls = ls;
|
|
|
@ -544,10 +543,6 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
|
|
|
f = fs->f;
|
|
|
|
f = fs->f;
|
|
|
|
f->source = ls->source;
|
|
|
|
f->source = ls->source;
|
|
|
|
f->maxstacksize = 2; /* registers 0/1 are always valid */
|
|
|
|
f->maxstacksize = 2; /* registers 0/1 are always valid */
|
|
|
|
fs->h = luaH_new(L);
|
|
|
|
|
|
|
|
/* anchor table of constants (to avoid being collected) */
|
|
|
|
|
|
|
|
sethvalue2s(L, L->top, fs->h);
|
|
|
|
|
|
|
|
incr_top(L);
|
|
|
|
|
|
|
|
enterblock(fs, bl, 0);
|
|
|
|
enterblock(fs, bl, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -572,9 +567,6 @@ static void close_func (LexState *ls) {
|
|
|
|
f->sizeupvalues = fs->nups;
|
|
|
|
f->sizeupvalues = fs->nups;
|
|
|
|
lua_assert(fs->bl == NULL);
|
|
|
|
lua_assert(fs->bl == NULL);
|
|
|
|
ls->fs = fs->prev;
|
|
|
|
ls->fs = fs->prev;
|
|
|
|
/* last token read was anchored in defunct function; must re-anchor it */
|
|
|
|
|
|
|
|
anchor_token(ls);
|
|
|
|
|
|
|
|
L->top--; /* pop table of constants */
|
|
|
|
|
|
|
|
luaC_checkGC(L);
|
|
|
|
luaC_checkGC(L);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -588,7 +580,7 @@ static void close_func (LexState *ls) {
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
** check whether current token is in the follow set of a block.
|
|
|
|
** check whether current token is in the follow set of a block.
|
|
|
|
** 'until' closes syntactical blocks, but do not close scope,
|
|
|
|
** 'until' closes syntactical blocks, but do not close scope,
|
|
|
|
** so it handled in separate.
|
|
|
|
** so it is handled in separate.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static int block_follow (LexState *ls, int withuntil) {
|
|
|
|
static int block_follow (LexState *ls, int withuntil) {
|
|
|
|
switch (ls->t.token) {
|
|
|
|
switch (ls->t.token) {
|
|
|
@ -602,7 +594,7 @@ static int block_follow (LexState *ls, int withuntil) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void statlist (LexState *ls) {
|
|
|
|
static void statlist (LexState *ls) {
|
|
|
|
/* statlist -> { stat [`;'] } */
|
|
|
|
/* statlist -> { stat [';'] } */
|
|
|
|
while (!block_follow(ls, 1)) {
|
|
|
|
while (!block_follow(ls, 1)) {
|
|
|
|
if (ls->t.token == TK_RETURN) {
|
|
|
|
if (ls->t.token == TK_RETURN) {
|
|
|
|
statement(ls);
|
|
|
|
statement(ls);
|
|
|
@ -643,14 +635,14 @@ static void yindex (LexState *ls, expdesc *v) {
|
|
|
|
struct ConsControl {
|
|
|
|
struct ConsControl {
|
|
|
|
expdesc v; /* last list item read */
|
|
|
|
expdesc v; /* last list item read */
|
|
|
|
expdesc *t; /* table descriptor */
|
|
|
|
expdesc *t; /* table descriptor */
|
|
|
|
int nh; /* total number of `record' elements */
|
|
|
|
int nh; /* total number of 'record' elements */
|
|
|
|
int na; /* total number of array elements */
|
|
|
|
int na; /* total number of array elements */
|
|
|
|
int tostore; /* number of array elements pending to be stored */
|
|
|
|
int tostore; /* number of array elements pending to be stored */
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void recfield (LexState *ls, struct ConsControl *cc) {
|
|
|
|
static void recfield (LexState *ls, struct ConsControl *cc) {
|
|
|
|
/* recfield -> (NAME | `['exp1`]') = exp1 */
|
|
|
|
/* recfield -> (NAME | '['exp1']') = exp1 */
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
int reg = ls->fs->freereg;
|
|
|
|
int reg = ls->fs->freereg;
|
|
|
|
expdesc key, val;
|
|
|
|
expdesc key, val;
|
|
|
@ -757,12 +749,12 @@ static void constructor (LexState *ls, expdesc *t) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void parlist (LexState *ls) {
|
|
|
|
static void parlist (LexState *ls) {
|
|
|
|
/* parlist -> [ param { `,' param } ] */
|
|
|
|
/* parlist -> [ param { ',' param } ] */
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
Proto *f = fs->f;
|
|
|
|
Proto *f = fs->f;
|
|
|
|
int nparams = 0;
|
|
|
|
int nparams = 0;
|
|
|
|
f->is_vararg = 0;
|
|
|
|
f->is_vararg = 0;
|
|
|
|
if (ls->t.token != ')') { /* is `parlist' not empty? */
|
|
|
|
if (ls->t.token != ')') { /* is 'parlist' not empty? */
|
|
|
|
do {
|
|
|
|
do {
|
|
|
|
switch (ls->t.token) {
|
|
|
|
switch (ls->t.token) {
|
|
|
|
case TK_NAME: { /* param -> NAME */
|
|
|
|
case TK_NAME: { /* param -> NAME */
|
|
|
@ -770,12 +762,12 @@ static void parlist (LexState *ls) {
|
|
|
|
nparams++;
|
|
|
|
nparams++;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case TK_DOTS: { /* param -> `...' */
|
|
|
|
case TK_DOTS: { /* param -> '...' */
|
|
|
|
luaX_next(ls);
|
|
|
|
luaX_next(ls);
|
|
|
|
f->is_vararg = 1;
|
|
|
|
f->is_vararg = 2; /* declared vararg */
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default: luaX_syntaxerror(ls, "<name> or " LUA_QL("...") " expected");
|
|
|
|
default: luaX_syntaxerror(ls, "<name> or '...' expected");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (!f->is_vararg && testnext(ls, ','));
|
|
|
|
} while (!f->is_vararg && testnext(ls, ','));
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -786,7 +778,7 @@ static void parlist (LexState *ls) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void body (LexState *ls, expdesc *e, int ismethod, int line) {
|
|
|
|
static void body (LexState *ls, expdesc *e, int ismethod, int line) {
|
|
|
|
/* body -> `(' parlist `)' block END */
|
|
|
|
/* body -> '(' parlist ')' block END */
|
|
|
|
FuncState new_fs;
|
|
|
|
FuncState new_fs;
|
|
|
|
BlockCnt bl;
|
|
|
|
BlockCnt bl;
|
|
|
|
new_fs.f = addprototype(ls);
|
|
|
|
new_fs.f = addprototype(ls);
|
|
|
@ -808,7 +800,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int explist (LexState *ls, expdesc *v) {
|
|
|
|
static int explist (LexState *ls, expdesc *v) {
|
|
|
|
/* explist -> expr { `,' expr } */
|
|
|
|
/* explist -> expr { ',' expr } */
|
|
|
|
int n = 1; /* at least one expression */
|
|
|
|
int n = 1; /* at least one expression */
|
|
|
|
expr(ls, v);
|
|
|
|
expr(ls, v);
|
|
|
|
while (testnext(ls, ',')) {
|
|
|
|
while (testnext(ls, ',')) {
|
|
|
@ -825,7 +817,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
|
|
|
|
expdesc args;
|
|
|
|
expdesc args;
|
|
|
|
int base, nparams;
|
|
|
|
int base, nparams;
|
|
|
|
switch (ls->t.token) {
|
|
|
|
switch (ls->t.token) {
|
|
|
|
case '(': { /* funcargs -> `(' [ explist ] `)' */
|
|
|
|
case '(': { /* funcargs -> '(' [ explist ] ')' */
|
|
|
|
luaX_next(ls);
|
|
|
|
luaX_next(ls);
|
|
|
|
if (ls->t.token == ')') /* arg list is empty? */
|
|
|
|
if (ls->t.token == ')') /* arg list is empty? */
|
|
|
|
args.k = VVOID;
|
|
|
|
args.k = VVOID;
|
|
|
@ -842,7 +834,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case TK_STRING: { /* funcargs -> STRING */
|
|
|
|
case TK_STRING: { /* funcargs -> STRING */
|
|
|
|
codestring(ls, &args, ls->t.seminfo.ts);
|
|
|
|
codestring(ls, &args, ls->t.seminfo.ts);
|
|
|
|
luaX_next(ls); /* must use `seminfo' before `next' */
|
|
|
|
luaX_next(ls); /* must use 'seminfo' before 'next' */
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
default: {
|
|
|
@ -908,14 +900,14 @@ static void suffixedexp (LexState *ls, expdesc *v) {
|
|
|
|
fieldsel(ls, v);
|
|
|
|
fieldsel(ls, v);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case '[': { /* `[' exp1 `]' */
|
|
|
|
case '[': { /* '[' exp1 ']' */
|
|
|
|
expdesc key;
|
|
|
|
expdesc key;
|
|
|
|
luaK_exp2anyregup(fs, v);
|
|
|
|
luaK_exp2anyregup(fs, v);
|
|
|
|
yindex(ls, &key);
|
|
|
|
yindex(ls, &key);
|
|
|
|
luaK_indexed(fs, v, &key);
|
|
|
|
luaK_indexed(fs, v, &key);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case ':': { /* `:' NAME funcargs */
|
|
|
|
case ':': { /* ':' NAME funcargs */
|
|
|
|
expdesc key;
|
|
|
|
expdesc key;
|
|
|
|
luaX_next(ls);
|
|
|
|
luaX_next(ls);
|
|
|
|
checkname(ls, &key);
|
|
|
|
checkname(ls, &key);
|
|
|
@ -935,14 +927,19 @@ static void suffixedexp (LexState *ls, expdesc *v) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void simpleexp (LexState *ls, expdesc *v) {
|
|
|
|
static void simpleexp (LexState *ls, expdesc *v) {
|
|
|
|
/* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
|
|
|
|
/* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... |
|
|
|
|
constructor | FUNCTION body | suffixedexp */
|
|
|
|
constructor | FUNCTION body | suffixedexp */
|
|
|
|
switch (ls->t.token) {
|
|
|
|
switch (ls->t.token) {
|
|
|
|
case TK_NUMBER: {
|
|
|
|
case TK_FLT: {
|
|
|
|
init_exp(v, VKNUM, 0);
|
|
|
|
init_exp(v, VKFLT, 0);
|
|
|
|
v->u.nval = ls->t.seminfo.r;
|
|
|
|
v->u.nval = ls->t.seminfo.r;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case TK_INT: {
|
|
|
|
|
|
|
|
init_exp(v, VKINT, 0);
|
|
|
|
|
|
|
|
v->u.ival = ls->t.seminfo.i;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
case TK_STRING: {
|
|
|
|
case TK_STRING: {
|
|
|
|
codestring(ls, v, ls->t.seminfo.ts);
|
|
|
|
codestring(ls, v, ls->t.seminfo.ts);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
@ -962,7 +959,8 @@ static void simpleexp (LexState *ls, expdesc *v) {
|
|
|
|
case TK_DOTS: { /* vararg */
|
|
|
|
case TK_DOTS: { /* vararg */
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
FuncState *fs = ls->fs;
|
|
|
|
check_condition(ls, fs->f->is_vararg,
|
|
|
|
check_condition(ls, fs->f->is_vararg,
|
|
|
|
"cannot use " LUA_QL("...") " outside a vararg function");
|
|
|
|
"cannot use '...' outside a vararg function");
|
|
|
|
|
|
|
|
fs->f->is_vararg = 1; /* function actually uses vararg */
|
|
|
|
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
|
|
|
|
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -988,6 +986,7 @@ static UnOpr getunopr (int op) {
|
|
|
|
switch (op) {
|
|
|
|
switch (op) {
|
|
|
|
case TK_NOT: return OPR_NOT;
|
|
|
|
case TK_NOT: return OPR_NOT;
|
|
|
|
case '-': return OPR_MINUS;
|
|
|
|
case '-': return OPR_MINUS;
|
|
|
|
|
|
|
|
case '~': return OPR_BNOT;
|
|
|
|
case '#': return OPR_LEN;
|
|
|
|
case '#': return OPR_LEN;
|
|
|
|
default: return OPR_NOUNOPR;
|
|
|
|
default: return OPR_NOUNOPR;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -999,9 +998,15 @@ static BinOpr getbinopr (int op) {
|
|
|
|
case '+': return OPR_ADD;
|
|
|
|
case '+': return OPR_ADD;
|
|
|
|
case '-': return OPR_SUB;
|
|
|
|
case '-': return OPR_SUB;
|
|
|
|
case '*': return OPR_MUL;
|
|
|
|
case '*': return OPR_MUL;
|
|
|
|
case '/': return OPR_DIV;
|
|
|
|
|
|
|
|
case '%': return OPR_MOD;
|
|
|
|
case '%': return OPR_MOD;
|
|
|
|
case '^': return OPR_POW;
|
|
|
|
case '^': return OPR_POW;
|
|
|
|
|
|
|
|
case '/': return OPR_DIV;
|
|
|
|
|
|
|
|
case TK_IDIV: return OPR_IDIV;
|
|
|
|
|
|
|
|
case '&': return OPR_BAND;
|
|
|
|
|
|
|
|
case '|': return OPR_BOR;
|
|
|
|
|
|
|
|
case '~': return OPR_BXOR;
|
|
|
|
|
|
|
|
case TK_SHL: return OPR_SHL;
|
|
|
|
|
|
|
|
case TK_SHR: return OPR_SHR;
|
|
|
|
case TK_CONCAT: return OPR_CONCAT;
|
|
|
|
case TK_CONCAT: return OPR_CONCAT;
|
|
|
|
case TK_NE: return OPR_NE;
|
|
|
|
case TK_NE: return OPR_NE;
|
|
|
|
case TK_EQ: return OPR_EQ;
|
|
|
|
case TK_EQ: return OPR_EQ;
|
|
|
@ -1020,19 +1025,24 @@ static const struct {
|
|
|
|
lu_byte left; /* left priority for each binary operator */
|
|
|
|
lu_byte left; /* left priority for each binary operator */
|
|
|
|
lu_byte right; /* right priority */
|
|
|
|
lu_byte right; /* right priority */
|
|
|
|
} priority[] = { /* ORDER OPR */
|
|
|
|
} priority[] = { /* ORDER OPR */
|
|
|
|
{6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */
|
|
|
|
{10, 10}, {10, 10}, /* '+' '-' */
|
|
|
|
{10, 9}, {5, 4}, /* ^, .. (right associative) */
|
|
|
|
{11, 11}, {11, 11}, /* '*' '%' */
|
|
|
|
|
|
|
|
{14, 13}, /* '^' (right associative) */
|
|
|
|
|
|
|
|
{11, 11}, {11, 11}, /* '/' '//' */
|
|
|
|
|
|
|
|
{6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */
|
|
|
|
|
|
|
|
{7, 7}, {7, 7}, /* '<<' '>>' */
|
|
|
|
|
|
|
|
{9, 8}, /* '..' (right associative) */
|
|
|
|
{3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */
|
|
|
|
{3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */
|
|
|
|
{3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */
|
|
|
|
{3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */
|
|
|
|
{2, 2}, {1, 1} /* and, or */
|
|
|
|
{2, 2}, {1, 1} /* and, or */
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#define UNARY_PRIORITY 8 /* priority for unary operators */
|
|
|
|
#define UNARY_PRIORITY 12 /* priority for unary operators */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
|
|
|
|
** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
|
|
|
|
** where `binop' is any binary operator with a priority higher than `limit'
|
|
|
|
** where 'binop' is any binary operator with a priority higher than 'limit'
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
|
|
|
|
static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
|
|
|
|
BinOpr op;
|
|
|
|
BinOpr op;
|
|
|
@ -1046,7 +1056,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
|
|
|
|
luaK_prefix(ls->fs, uop, v, line);
|
|
|
|
luaK_prefix(ls->fs, uop, v, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else simpleexp(ls, v);
|
|
|
|
else simpleexp(ls, v);
|
|
|
|
/* expand while operators have priorities higher than `limit' */
|
|
|
|
/* expand while operators have priorities higher than 'limit' */
|
|
|
|
op = getbinopr(ls->t.token);
|
|
|
|
op = getbinopr(ls->t.token);
|
|
|
|
while (op != OPR_NOBINOPR && priority[op].left > limit) {
|
|
|
|
while (op != OPR_NOBINOPR && priority[op].left > limit) {
|
|
|
|
expdesc v2;
|
|
|
|
expdesc v2;
|
|
|
@ -1146,7 +1156,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
|
|
|
|
"C levels");
|
|
|
|
"C levels");
|
|
|
|
assignment(ls, &nv, nvars+1);
|
|
|
|
assignment(ls, &nv, nvars+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* assignment -> `=' explist */
|
|
|
|
else { /* assignment -> '=' explist */
|
|
|
|
int nexps;
|
|
|
|
int nexps;
|
|
|
|
checknext(ls, '=');
|
|
|
|
checknext(ls, '=');
|
|
|
|
nexps = explist(ls, &e);
|
|
|
|
nexps = explist(ls, &e);
|
|
|
@ -1170,7 +1180,7 @@ static int cond (LexState *ls) {
|
|
|
|
/* cond -> exp */
|
|
|
|
/* cond -> exp */
|
|
|
|
expdesc v;
|
|
|
|
expdesc v;
|
|
|
|
expr(ls, &v); /* read condition */
|
|
|
|
expr(ls, &v); /* read condition */
|
|
|
|
if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */
|
|
|
|
if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */
|
|
|
|
luaK_goiftrue(ls->fs, &v);
|
|
|
|
luaK_goiftrue(ls->fs, &v);
|
|
|
|
return v.f;
|
|
|
|
return v.f;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1195,9 +1205,9 @@ static void gotostat (LexState *ls, int pc) {
|
|
|
|
static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
|
|
|
|
static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
|
|
|
|
int i;
|
|
|
|
int i;
|
|
|
|
for (i = fs->bl->firstlabel; i < ll->n; i++) {
|
|
|
|
for (i = fs->bl->firstlabel; i < ll->n; i++) {
|
|
|
|
if (luaS_eqstr(label, ll->arr[i].name)) {
|
|
|
|
if (eqstr(label, ll->arr[i].name)) {
|
|
|
|
const char *msg = luaO_pushfstring(fs->ls->L,
|
|
|
|
const char *msg = luaO_pushfstring(fs->ls->L,
|
|
|
|
"label " LUA_QS " already defined on line %d",
|
|
|
|
"label '%s' already defined on line %d",
|
|
|
|
getstr(label), ll->arr[i].line);
|
|
|
|
getstr(label), ll->arr[i].line);
|
|
|
|
semerror(fs->ls, msg);
|
|
|
|
semerror(fs->ls, msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1220,7 +1230,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
|
|
|
|
checkrepeated(fs, ll, label); /* check for repeated labels */
|
|
|
|
checkrepeated(fs, ll, label); /* check for repeated labels */
|
|
|
|
checknext(ls, TK_DBCOLON); /* skip double colon */
|
|
|
|
checknext(ls, TK_DBCOLON); /* skip double colon */
|
|
|
|
/* create new entry for this label */
|
|
|
|
/* create new entry for this label */
|
|
|
|
l = newlabelentry(ls, ll, label, line, fs->pc);
|
|
|
|
l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
|
|
|
|
skipnoopstat(ls); /* skip other no-op statements */
|
|
|
|
skipnoopstat(ls); /* skip other no-op statements */
|
|
|
|
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
|
|
|
|
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
|
|
|
|
/* assume that locals are already out of scope */
|
|
|
|
/* assume that locals are already out of scope */
|
|
|
@ -1321,7 +1331,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
|
|
|
|
if (testnext(ls, ','))
|
|
|
|
if (testnext(ls, ','))
|
|
|
|
exp1(ls); /* optional step */
|
|
|
|
exp1(ls); /* optional step */
|
|
|
|
else { /* default step = 1 */
|
|
|
|
else { /* default step = 1 */
|
|
|
|
luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1));
|
|
|
|
luaK_codek(fs, fs->freereg, luaK_intK(fs, 1));
|
|
|
|
luaK_reserveregs(fs, 1);
|
|
|
|
luaK_reserveregs(fs, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
forbody(ls, base, line, 1, 1);
|
|
|
|
forbody(ls, base, line, 1, 1);
|
|
|
@ -1359,15 +1369,15 @@ static void forstat (LexState *ls, int line) {
|
|
|
|
TString *varname;
|
|
|
|
TString *varname;
|
|
|
|
BlockCnt bl;
|
|
|
|
BlockCnt bl;
|
|
|
|
enterblock(fs, &bl, 1); /* scope for loop and control variables */
|
|
|
|
enterblock(fs, &bl, 1); /* scope for loop and control variables */
|
|
|
|
luaX_next(ls); /* skip `for' */
|
|
|
|
luaX_next(ls); /* skip 'for' */
|
|
|
|
varname = str_checkname(ls); /* first variable name */
|
|
|
|
varname = str_checkname(ls); /* first variable name */
|
|
|
|
switch (ls->t.token) {
|
|
|
|
switch (ls->t.token) {
|
|
|
|
case '=': fornum(ls, varname, line); break;
|
|
|
|
case '=': fornum(ls, varname, line); break;
|
|
|
|
case ',': case TK_IN: forlist(ls, varname); break;
|
|
|
|
case ',': case TK_IN: forlist(ls, varname); break;
|
|
|
|
default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected");
|
|
|
|
default: luaX_syntaxerror(ls, "'=' or 'in' expected");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
check_match(ls, TK_END, TK_FOR, line);
|
|
|
|
check_match(ls, TK_END, TK_FOR, line);
|
|
|
|
leaveblock(fs); /* loop scope (`break' jumps to this point) */
|
|
|
|
leaveblock(fs); /* loop scope ('break' jumps to this point) */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1397,7 +1407,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
|
|
|
|
enterblock(fs, &bl, 0);
|
|
|
|
enterblock(fs, &bl, 0);
|
|
|
|
jf = v.f;
|
|
|
|
jf = v.f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
statlist(ls); /* `then' part */
|
|
|
|
statlist(ls); /* 'then' part */
|
|
|
|
leaveblock(fs);
|
|
|
|
leaveblock(fs);
|
|
|
|
if (ls->t.token == TK_ELSE ||
|
|
|
|
if (ls->t.token == TK_ELSE ||
|
|
|
|
ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */
|
|
|
|
ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */
|
|
|
@ -1414,7 +1424,7 @@ static void ifstat (LexState *ls, int line) {
|
|
|
|
while (ls->t.token == TK_ELSEIF)
|
|
|
|
while (ls->t.token == TK_ELSEIF)
|
|
|
|
test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */
|
|
|
|
test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */
|
|
|
|
if (testnext(ls, TK_ELSE))
|
|
|
|
if (testnext(ls, TK_ELSE))
|
|
|
|
block(ls); /* `else' part */
|
|
|
|
block(ls); /* 'else' part */
|
|
|
|
check_match(ls, TK_END, TK_IF, line);
|
|
|
|
check_match(ls, TK_END, TK_IF, line);
|
|
|
|
luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */
|
|
|
|
luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1432,7 +1442,7 @@ static void localfunc (LexState *ls) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void localstat (LexState *ls) {
|
|
|
|
static void localstat (LexState *ls) {
|
|
|
|
/* stat -> LOCAL NAME {`,' NAME} [`=' explist] */
|
|
|
|
/* stat -> LOCAL NAME {',' NAME} ['=' explist] */
|
|
|
|
int nvars = 0;
|
|
|
|
int nvars = 0;
|
|
|
|
int nexps;
|
|
|
|
int nexps;
|
|
|
|
expdesc e;
|
|
|
|
expdesc e;
|
|
|
@ -1452,7 +1462,7 @@ static void localstat (LexState *ls) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int funcname (LexState *ls, expdesc *v) {
|
|
|
|
static int funcname (LexState *ls, expdesc *v) {
|
|
|
|
/* funcname -> NAME {fieldsel} [`:' NAME] */
|
|
|
|
/* funcname -> NAME {fieldsel} [':' NAME] */
|
|
|
|
int ismethod = 0;
|
|
|
|
int ismethod = 0;
|
|
|
|
singlevar(ls, v);
|
|
|
|
singlevar(ls, v);
|
|
|
|
while (ls->t.token == '.')
|
|
|
|
while (ls->t.token == '.')
|
|
|
@ -1473,7 +1483,7 @@ static void funcstat (LexState *ls, int line) {
|
|
|
|
ismethod = funcname(ls, &v);
|
|
|
|
ismethod = funcname(ls, &v);
|
|
|
|
body(ls, &b, ismethod, line);
|
|
|
|
body(ls, &b, ismethod, line);
|
|
|
|
luaK_storevar(ls->fs, &v, &b);
|
|
|
|
luaK_storevar(ls->fs, &v, &b);
|
|
|
|
luaK_fixline(ls->fs, line); /* definition `happens' in the first line */
|
|
|
|
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1488,7 +1498,7 @@ static void exprstat (LexState *ls) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* stat -> func */
|
|
|
|
else { /* stat -> func */
|
|
|
|
check_condition(ls, v.v.k == VCALL, "syntax error");
|
|
|
|
check_condition(ls, v.v.k == VCALL, "syntax error");
|
|
|
|
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
|
|
|
|
SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1505,8 +1515,8 @@ static void retstat (LexState *ls) {
|
|
|
|
if (hasmultret(e.k)) {
|
|
|
|
if (hasmultret(e.k)) {
|
|
|
|
luaK_setmultret(fs, &e);
|
|
|
|
luaK_setmultret(fs, &e);
|
|
|
|
if (e.k == VCALL && nret == 1) { /* tail call? */
|
|
|
|
if (e.k == VCALL && nret == 1) { /* tail call? */
|
|
|
|
SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
|
|
|
|
SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
|
|
|
|
lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
|
|
|
|
lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
first = fs->nactvar;
|
|
|
|
first = fs->nactvar;
|
|
|
|
nret = LUA_MULTRET; /* return all values */
|
|
|
|
nret = LUA_MULTRET; /* return all values */
|
|
|
@ -1515,8 +1525,8 @@ static void retstat (LexState *ls) {
|
|
|
|
if (nret == 1) /* only one single value? */
|
|
|
|
if (nret == 1) /* only one single value? */
|
|
|
|
first = luaK_exp2anyreg(fs, &e);
|
|
|
|
first = luaK_exp2anyreg(fs, &e);
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */
|
|
|
|
luaK_exp2nextreg(fs, &e); /* values must go to the stack */
|
|
|
|
first = fs->nactvar; /* return all `active' values */
|
|
|
|
first = fs->nactvar; /* return all active values */
|
|
|
|
lua_assert(nret == fs->freereg - first);
|
|
|
|
lua_assert(nret == fs->freereg - first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1605,7 +1615,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
|
|
|
BlockCnt bl;
|
|
|
|
BlockCnt bl;
|
|
|
|
expdesc v;
|
|
|
|
expdesc v;
|
|
|
|
open_func(ls, fs, &bl);
|
|
|
|
open_func(ls, fs, &bl);
|
|
|
|
fs->f->is_vararg = 1; /* main function is always vararg */
|
|
|
|
fs->f->is_vararg = 2; /* main function is always declared vararg */
|
|
|
|
init_exp(&v, VLOCAL, 0); /* create and... */
|
|
|
|
init_exp(&v, VLOCAL, 0); /* create and... */
|
|
|
|
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
|
|
|
|
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
|
|
|
|
luaX_next(ls); /* read first token */
|
|
|
|
luaX_next(ls); /* read first token */
|
|
|
@ -1615,16 +1625,19 @@ static void mainfunc (LexState *ls, FuncState *fs) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
|
|
|
LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
|
|
|
Dyndata *dyd, const char *name, int firstchar) {
|
|
|
|
Dyndata *dyd, const char *name, int firstchar) {
|
|
|
|
LexState lexstate;
|
|
|
|
LexState lexstate;
|
|
|
|
FuncState funcstate;
|
|
|
|
FuncState funcstate;
|
|
|
|
Closure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
|
|
|
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
|
|
|
/* anchor closure (to avoid being collected) */
|
|
|
|
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
|
|
|
|
setclLvalue(L, L->top, cl);
|
|
|
|
luaD_inctop(L);
|
|
|
|
incr_top(L);
|
|
|
|
lexstate.h = luaH_new(L); /* create table for scanner */
|
|
|
|
funcstate.f = cl->l.p = luaF_newproto(L);
|
|
|
|
sethvalue(L, L->top, lexstate.h); /* anchor it */
|
|
|
|
|
|
|
|
luaD_inctop(L);
|
|
|
|
|
|
|
|
funcstate.f = cl->p = luaF_newproto(L);
|
|
|
|
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
|
|
|
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
|
|
|
|
|
|
|
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
|
|
|
|
lexstate.buff = buff;
|
|
|
|
lexstate.buff = buff;
|
|
|
|
lexstate.dyd = dyd;
|
|
|
|
lexstate.dyd = dyd;
|
|
|
|
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
|
|
|
|
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
|
|
|
@ -1633,6 +1646,7 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
|
|
|
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
|
|
|
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
|
|
|
/* all scopes should be correctly finished */
|
|
|
|
/* all scopes should be correctly finished */
|
|
|
|
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
|
|
|
|
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
|
|
|
|
return cl; /* it's on the stack too */
|
|
|
|
L->top--; /* remove scanner's table */
|
|
|
|
|
|
|
|
return cl; /* closure is on the stack, too */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|