summaryrefslogtreecommitdiff
path: root/src/lparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lparser.c')
-rw-r--r--src/lparser.c184
1 files changed, 95 insertions, 89 deletions
diff --git a/src/lparser.c b/src/lparser.c
index cc21f67f..762cb4fc 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.75 2010/01/06 11:48:02 roberto Exp $
+** $Id: lparser.c,v 2.86 2010/05/15 13:32:02 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -74,9 +74,10 @@ static void error_expected (LexState *ls, int token) {
static void errorlimit (FuncState *fs, int limit, const char *what) {
const char *msg;
- const char *where = (fs->f->linedefined == 0) ?
- "main function" :
- luaO_pushfstring(fs->L, "function at line %d", fs->f->linedefined);
+ int line = fs->f->linedefined;
+ const char *where = (line == 0)
+ ? "main function"
+ : luaO_pushfstring(fs->L, "function at line %d", line);
msg = luaO_pushfstring(fs->L, "too many %s (limit is %d) in %s",
what, limit, where);
luaX_syntaxerror(fs->ls, msg);
@@ -207,27 +208,27 @@ static void removevars (FuncState *fs, int tolevel) {
}
-static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
+static int searchupvalue (FuncState *fs, TString *name) {
int i;
+ Upvaldesc *up = fs->f->upvalues;
+ for (i = 0; i < fs->nups; i++) {
+ if (eqstr(up[i].name, name)) return i;
+ }
+ return -1; /* not found */
+}
+
+
+static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
Proto *f = fs->f;
int oldsize = f->sizeupvalues;
- int instk = (v->k == VLOCAL);
- lua_assert(instk || v->k == VUPVAL);
- for (i=0; i<fs->nups; i++) {
- if (f->upvalues[i].instack == instk && f->upvalues[i].idx == v->u.s.info) {
- lua_assert(f->upvalues[i].name == name);
- return i;
- }
- }
- /* new one */
checklimit(fs, fs->nups + 1, UCHAR_MAX, "upvalues");
luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, UCHAR_MAX, "upvalues");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
+ f->upvalues[fs->nups].instack = (v->k == VLOCAL);
+ f->upvalues[fs->nups].idx = cast_byte(v->u.s.info);
f->upvalues[fs->nups].name = name;
luaC_objbarrier(fs->L, f, name);
- f->upvalues[fs->nups].instack = cast_byte(instk);
- f->upvalues[fs->nups].idx = cast_byte(v->u.s.info);
return fs->nups++;
}
@@ -235,13 +236,17 @@ static int indexupvalue (FuncState *fs, TString *name, expdesc *v) {
static int searchvar (FuncState *fs, TString *n) {
int i;
for (i=fs->nactvar-1; i >= 0; i--) {
- if (n == getlocvar(fs, i)->varname)
+ if (eqstr(n, getlocvar(fs, i)->varname))
return i;
}
return -1; /* not found */
}
+/*
+ Mark block where variable at given level was defined
+ (to emit OP_CLOSE later).
+*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
while (bl && bl->nactvar > level) bl = bl->previous;
@@ -249,22 +254,30 @@ static void markupval (FuncState *fs, int level) {
}
+/*
+ Find variable with given name 'n'. If it is an upvalue, add this
+ upvalue into all intermediate functions.
+*/
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
- return VGLOBAL; /* default is global variable */
+ return VVOID; /* default is global */
else {
- int v = searchvar(fs, n); /* look up at current level */
- if (v >= 0) {
- init_exp(var, VLOCAL, v);
+ int v = searchvar(fs, n); /* look up locals at current level */
+ if (v >= 0) { /* found? */
+ init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
}
- else { /* not found at current level; try upper one */
- if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
- return VGLOBAL;
- var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */
- var->k = VUPVAL; /* upvalue in this level */
+ else { /* not found as local at current level; try upvalues */
+ int idx = searchupvalue(fs, n); /* try existing upvalues */
+ if (idx < 0) { /* not found? */
+ if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
+ return VVOID; /* not found; is a global */
+ /* else was LOCAL or UPVAL */
+ idx = newupvalue(fs, n, var); /* will be a new upvalue */
+ }
+ init_exp(var, VUPVAL, idx);
return VUPVAL;
}
}
@@ -274,15 +287,12 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
- if (singlevaraux(fs, varname, var, 1) == VGLOBAL) {
- if (fs->envreg == NO_REG) /* regular global? */
- init_exp(var, VGLOBAL, luaK_stringK(fs, varname));
- else { /* "globals" are in current lexical environment */
- expdesc key;
- init_exp(var, VLOCAL, fs->envreg); /* current environment */
- codestring(ls, &key, varname); /* key is variable name */
- luaK_indexed(fs, var, &key); /* env[varname] */
- }
+ if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
+ expdesc key;
+ singlevaraux(fs, ls->envn, var, 1); /* get _ENV variable */
+ lua_assert(var->k == VLOCAL || var->k == VUPVAL);
+ codestring(ls, &key, varname); /* key is variable name */
+ luaK_indexed(fs, var, &key); /* env[varname] */
}
}
@@ -351,7 +361,6 @@ static void pushclosure (LexState *ls, Proto *clp, expdesc *v) {
while (oldsize < f->sizep) f->p[oldsize++] = NULL;
f->p[fs->np++] = clp;
/* initial environment for new function is current lexical environment */
- clp->envreg = fs->envreg;
luaC_objbarrier(ls->L, f, clp);
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
}
@@ -374,7 +383,6 @@ static void open_func (LexState *ls, FuncState *fs) {
fs->nlocvars = 0;
fs->nactvar = 0;
fs->firstlocal = ls->varl->nactvar;
- fs->envreg = NO_REG;
fs->bl = NULL;
f = luaF_newproto(L);
fs->f = f;
@@ -418,26 +426,36 @@ static void close_func (LexState *ls) {
}
+/*
+** opens the main function, which is a regular vararg function with an
+** upvalue named '_ENV'
+*/
+static void open_mainfunc (LexState *ls, FuncState *fs) {
+ expdesc v;
+ open_func(ls, fs);
+ fs->f->is_vararg = 1; /* main function is always vararg */
+ init_exp(&v, VLOCAL, 0);
+ newupvalue(fs, ls->envn, &v); /* create '_ENV' upvalue */
+}
+
+
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Varlist *varl,
const char *name) {
- struct LexState lexstate;
- struct FuncState funcstate;
+ LexState lexstate;
+ FuncState funcstate;
TString *tname = luaS_new(L, name);
setsvalue2s(L, L->top, tname); /* push name to protect it */
incr_top(L);
lexstate.buff = buff;
lexstate.varl = varl;
luaX_setinput(L, &lexstate, z, tname);
- open_func(&lexstate, &funcstate);
- funcstate.f->is_vararg = 1; /* main function is always vararg */
+ open_mainfunc(&lexstate, &funcstate);
luaX_next(&lexstate); /* read first token */
- chunk(&lexstate);
+ chunk(&lexstate); /* read main chunk */
check(&lexstate, TK_EOS);
close_func(&lexstate);
L->top--; /* pop name */
- lua_assert(funcstate.prev == NULL);
- lua_assert(funcstate.nups == 0);
- lua_assert(lexstate.fs == NULL);
+ lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
return funcstate.f;
}
@@ -452,7 +470,7 @@ static void fieldsel (LexState *ls, expdesc *v) {
/* fieldsel -> ['.' | ':'] NAME */
FuncState *fs = ls->fs;
expdesc key;
- luaK_exp2anyreg(fs, v);
+ luaK_exp2anyregup(fs, v);
luaX_next(ls); /* skip the dot or colon */
checkname(ls, &key);
luaK_indexed(fs, v, &key);
@@ -653,15 +671,12 @@ static int explist1 (LexState *ls, expdesc *v) {
}
-static void funcargs (LexState *ls, expdesc *f) {
+static void funcargs (LexState *ls, expdesc *f, int line) {
FuncState *fs = ls->fs;
expdesc args;
int base, nparams;
- int line = ls->linenumber;
switch (ls->t.token) {
case '(': { /* funcargs -> `(' [ explist1 ] `)' */
- if (line != ls->lastline)
- luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
luaX_next(ls);
if (ls->t.token == ')') /* arg list is empty? */
args.k = VVOID;
@@ -738,6 +753,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
/* primaryexp ->
prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
FuncState *fs = ls->fs;
+ int line = ls->linenumber;
prefixexp(ls, v);
for (;;) {
switch (ls->t.token) {
@@ -747,7 +763,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
}
case '[': { /* `[' exp1 `]' */
expdesc key;
- luaK_exp2anyreg(fs, v);
+ luaK_exp2anyregup(fs, v);
yindex(ls, &key);
luaK_indexed(fs, v, &key);
break;
@@ -757,12 +773,12 @@ static void primaryexp (LexState *ls, expdesc *v) {
luaX_next(ls);
checkname(ls, &key);
luaK_self(fs, v, &key);
- funcargs(ls, v);
+ funcargs(ls, v, line);
break;
}
case '(': case TK_STRING: case '{': { /* funcargs */
luaK_exp2nextreg(fs, v);
- funcargs(ls, v);
+ funcargs(ls, v, line);
break;
}
default: return;
@@ -877,9 +893,10 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
enterlevel(ls);
uop = getunopr(ls->t.token);
if (uop != OPR_NOUNOPR) {
+ int line = ls->linenumber;
luaX_next(ls);
subexpr(ls, v, UNARY_PRIORITY);
- luaK_prefix(ls->fs, uop, v);
+ luaK_prefix(ls->fs, uop, v, line);
}
else simpleexp(ls, v);
/* expand while operators have priorities higher than `limit' */
@@ -887,11 +904,12 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
while (op != OPR_NOBINOPR && priority[op].left > limit) {
expdesc v2;
BinOpr nextop;
+ int line = ls->linenumber;
luaX_next(ls);
luaK_infix(ls->fs, op, v);
/* read sub-expression with higher priority */
nextop = subexpr(ls, &v2, priority[op].right);
- luaK_posfix(ls->fs, op, v, &v2);
+ luaK_posfix(ls->fs, op, v, &v2, line);
op = nextop;
}
leavelevel(ls);
@@ -951,24 +969,27 @@ struct LHS_assign {
** local value in a safe place and use this safe copy in the previous
** assignment.
*/
-static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
+static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v,
+ expkind ix, OpCode op) {
FuncState *fs = ls->fs;
int extra = fs->freereg; /* eventual position to save local variable */
int conflict = 0;
for (; lh; lh = lh->prev) {
- if (lh->v.k == VINDEXED) {
+ if (lh->v.k == ix) {
if (lh->v.u.s.info == v->u.s.info) { /* conflict? */
conflict = 1;
+ lh->v.k = VINDEXED;
lh->v.u.s.info = extra; /* previous assignment will use safe copy */
}
- if (lh->v.u.s.aux == v->u.s.info) { /* conflict? */
+ if (v->k == VLOCAL && lh->v.u.s.aux == v->u.s.info) { /* conflict? */
conflict = 1;
+ lua_assert(lh->v.k == VINDEXED);
lh->v.u.s.aux = extra; /* previous assignment will use safe copy */
}
}
}
if (conflict) {
- luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.s.info, 0); /* make copy */
+ luaK_codeABC(fs, op, fs->freereg, v->u.s.info, 0); /* make copy */
luaK_reserveregs(fs, 1);
}
}
@@ -976,14 +997,16 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
expdesc e;
- check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
+ check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXEDUP,
"syntax error");
if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */
struct LHS_assign nv;
nv.prev = lh;
primaryexp(ls, &nv.v);
if (nv.v.k == VLOCAL)
- check_conflict(ls, lh, &nv.v);
+ check_conflict(ls, lh, &nv.v, VINDEXED, OP_MOVE);
+ else if (nv.v.k == VUPVAL)
+ check_conflict(ls, lh, &nv.v, VINDEXEDUP, OP_GETUPVAL);
checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls,
"variable names");
assignment(ls, &nv, nvars+1);
@@ -1274,24 +1297,6 @@ static void funcstat (LexState *ls, int line) {
}
-static void instat (LexState *ls, int line) {
- /* instat -> IN exp DO block END */
- FuncState *fs = ls->fs;
- int oldenv = fs->envreg; /* save current environment */
- BlockCnt bl;
- luaX_next(ls); /* skip IN */
- enterblock(fs, &bl, 0); /* scope for environment variable */
- new_localvarliteral(ls, "(environment)");
- fs->envreg = exp1(ls); /* new environment */
- adjustlocalvars(ls, 1);
- checknext(ls, TK_DO);
- block(ls);
- leaveblock(fs);
- check_match(ls, TK_END, TK_IN, line);
- fs->envreg = oldenv; /* restore outer environment */
-}
-
-
static void exprstat (LexState *ls) {
/* stat -> func | assignment */
FuncState *fs = ls->fs;
@@ -1311,7 +1316,6 @@ static void retstat (LexState *ls) {
FuncState *fs = ls->fs;
expdesc e;
int first, nret; /* registers with returned values */
- luaX_next(ls); /* skip RETURN */
if (block_follow(ls->t.token) || ls->t.token == ';')
first = nret = 0; /* return no values */
else {
@@ -1342,6 +1346,10 @@ static void retstat (LexState *ls) {
static int statement (LexState *ls) {
int line = ls->linenumber; /* may be needed for error messages */
switch (ls->t.token) {
+ case ';': { /* stat -> ';' (empty statement) */
+ luaX_next(ls); /* skip ';' */
+ return 0;
+ }
case TK_IF: { /* stat -> ifstat */
ifstat(ls, line);
return 0;
@@ -1356,10 +1364,6 @@ static int statement (LexState *ls) {
check_match(ls, TK_END, TK_DO, line);
return 0;
}
- case TK_IN: {
- instat(ls, line);
- return 0;
- }
case TK_FOR: { /* stat -> forstat */
forstat(ls, line);
return 0;
@@ -1368,8 +1372,8 @@ static int statement (LexState *ls) {
repeatstat(ls, line);
return 0;
}
- case TK_FUNCTION: {
- funcstat(ls, line); /* stat -> funcstat */
+ case TK_FUNCTION: { /* stat -> funcstat */
+ funcstat(ls, line);
return 0;
}
case TK_LOCAL: { /* stat -> localstat */
@@ -1381,6 +1385,7 @@ static int statement (LexState *ls) {
return 0;
}
case TK_RETURN: { /* stat -> retstat */
+ luaX_next(ls); /* skip RETURN */
retstat(ls);
return 1; /* must be last statement */
}
@@ -1389,9 +1394,9 @@ static int statement (LexState *ls) {
breakstat(ls);
return 1; /* must be last statement */
}
- default: {
+ default: { /* stat -> func | assignment */
exprstat(ls);
- return 0; /* to avoid warnings */
+ return 0;
}
}
}
@@ -1403,7 +1408,8 @@ static void chunk (LexState *ls) {
enterlevel(ls);
while (!islast && !block_follow(ls->t.token)) {
islast = statement(ls);
- testnext(ls, ';');
+ if (islast)
+ testnext(ls, ';');
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */