xref: /freebsd/contrib/lua/src/lparser.c (revision bf9580a118e399f3f3d37b3466877ba1c2c2a6f6)
18e3e3a7aSWarner Losh /*
2e112e9d2SKyle Evans ** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $
38e3e3a7aSWarner Losh ** Lua Parser
48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h
58e3e3a7aSWarner Losh */
68e3e3a7aSWarner Losh 
78e3e3a7aSWarner Losh #define lparser_c
88e3e3a7aSWarner Losh #define LUA_CORE
98e3e3a7aSWarner Losh 
108e3e3a7aSWarner Losh #include "lprefix.h"
118e3e3a7aSWarner Losh 
128e3e3a7aSWarner Losh 
138e3e3a7aSWarner Losh #include <string.h>
148e3e3a7aSWarner Losh 
158e3e3a7aSWarner Losh #include "lua.h"
168e3e3a7aSWarner Losh 
178e3e3a7aSWarner Losh #include "lcode.h"
188e3e3a7aSWarner Losh #include "ldebug.h"
198e3e3a7aSWarner Losh #include "ldo.h"
208e3e3a7aSWarner Losh #include "lfunc.h"
218e3e3a7aSWarner Losh #include "llex.h"
228e3e3a7aSWarner Losh #include "lmem.h"
238e3e3a7aSWarner Losh #include "lobject.h"
248e3e3a7aSWarner Losh #include "lopcodes.h"
258e3e3a7aSWarner Losh #include "lparser.h"
268e3e3a7aSWarner Losh #include "lstate.h"
278e3e3a7aSWarner Losh #include "lstring.h"
288e3e3a7aSWarner Losh #include "ltable.h"
298e3e3a7aSWarner Losh 
308e3e3a7aSWarner Losh 
318e3e3a7aSWarner Losh 
328e3e3a7aSWarner Losh /* maximum number of local variables per function (must be smaller
338e3e3a7aSWarner Losh    than 250, due to the bytecode format) */
348e3e3a7aSWarner Losh #define MAXVARS		200
358e3e3a7aSWarner Losh 
368e3e3a7aSWarner Losh 
378e3e3a7aSWarner Losh #define hasmultret(k)		((k) == VCALL || (k) == VVARARG)
388e3e3a7aSWarner Losh 
398e3e3a7aSWarner Losh 
408e3e3a7aSWarner Losh /* because all strings are unified by the scanner, the parser
418e3e3a7aSWarner Losh    can use pointer equality for string equality */
428e3e3a7aSWarner Losh #define eqstr(a,b)	((a) == (b))
438e3e3a7aSWarner Losh 
448e3e3a7aSWarner Losh 
458e3e3a7aSWarner Losh /*
468e3e3a7aSWarner Losh ** nodes for block list (list of active blocks)
478e3e3a7aSWarner Losh */
488e3e3a7aSWarner Losh typedef struct BlockCnt {
498e3e3a7aSWarner Losh   struct BlockCnt *previous;  /* chain */
508e3e3a7aSWarner Losh   int firstlabel;  /* index of first label in this block */
518e3e3a7aSWarner Losh   int firstgoto;  /* index of first pending goto in this block */
528e3e3a7aSWarner Losh   lu_byte nactvar;  /* # active locals outside the block */
538e3e3a7aSWarner Losh   lu_byte upval;  /* true if some variable in the block is an upvalue */
548e3e3a7aSWarner Losh   lu_byte isloop;  /* true if 'block' is a loop */
558e3e3a7aSWarner Losh } BlockCnt;
568e3e3a7aSWarner Losh 
578e3e3a7aSWarner Losh 
588e3e3a7aSWarner Losh 
598e3e3a7aSWarner Losh /*
608e3e3a7aSWarner Losh ** prototypes for recursive non-terminal functions
618e3e3a7aSWarner Losh */
628e3e3a7aSWarner Losh static void statement (LexState *ls);
638e3e3a7aSWarner Losh static void expr (LexState *ls, expdesc *v);
648e3e3a7aSWarner Losh 
658e3e3a7aSWarner Losh 
668e3e3a7aSWarner Losh /* semantic error */
678e3e3a7aSWarner Losh static l_noret semerror (LexState *ls, const char *msg) {
688e3e3a7aSWarner Losh   ls->t.token = 0;  /* remove "near <token>" from final message */
698e3e3a7aSWarner Losh   luaX_syntaxerror(ls, msg);
708e3e3a7aSWarner Losh }
718e3e3a7aSWarner Losh 
728e3e3a7aSWarner Losh 
738e3e3a7aSWarner Losh static l_noret error_expected (LexState *ls, int token) {
748e3e3a7aSWarner Losh   luaX_syntaxerror(ls,
758e3e3a7aSWarner Losh       luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token)));
768e3e3a7aSWarner Losh }
778e3e3a7aSWarner Losh 
788e3e3a7aSWarner Losh 
798e3e3a7aSWarner Losh static l_noret errorlimit (FuncState *fs, int limit, const char *what) {
808e3e3a7aSWarner Losh   lua_State *L = fs->ls->L;
818e3e3a7aSWarner Losh   const char *msg;
828e3e3a7aSWarner Losh   int line = fs->f->linedefined;
838e3e3a7aSWarner Losh   const char *where = (line == 0)
848e3e3a7aSWarner Losh                       ? "main function"
858e3e3a7aSWarner Losh                       : luaO_pushfstring(L, "function at line %d", line);
868e3e3a7aSWarner Losh   msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s",
878e3e3a7aSWarner Losh                              what, limit, where);
888e3e3a7aSWarner Losh   luaX_syntaxerror(fs->ls, msg);
898e3e3a7aSWarner Losh }
908e3e3a7aSWarner Losh 
918e3e3a7aSWarner Losh 
928e3e3a7aSWarner Losh static void checklimit (FuncState *fs, int v, int l, const char *what) {
938e3e3a7aSWarner Losh   if (v > l) errorlimit(fs, l, what);
948e3e3a7aSWarner Losh }
958e3e3a7aSWarner Losh 
968e3e3a7aSWarner Losh 
978e3e3a7aSWarner Losh static int testnext (LexState *ls, int c) {
988e3e3a7aSWarner Losh   if (ls->t.token == c) {
998e3e3a7aSWarner Losh     luaX_next(ls);
1008e3e3a7aSWarner Losh     return 1;
1018e3e3a7aSWarner Losh   }
1028e3e3a7aSWarner Losh   else return 0;
1038e3e3a7aSWarner Losh }
1048e3e3a7aSWarner Losh 
1058e3e3a7aSWarner Losh 
1068e3e3a7aSWarner Losh static void check (LexState *ls, int c) {
1078e3e3a7aSWarner Losh   if (ls->t.token != c)
1088e3e3a7aSWarner Losh     error_expected(ls, c);
1098e3e3a7aSWarner Losh }
1108e3e3a7aSWarner Losh 
1118e3e3a7aSWarner Losh 
1128e3e3a7aSWarner Losh static void checknext (LexState *ls, int c) {
1138e3e3a7aSWarner Losh   check(ls, c);
1148e3e3a7aSWarner Losh   luaX_next(ls);
1158e3e3a7aSWarner Losh }
1168e3e3a7aSWarner Losh 
1178e3e3a7aSWarner Losh 
1188e3e3a7aSWarner Losh #define check_condition(ls,c,msg)	{ if (!(c)) luaX_syntaxerror(ls, msg); }
1198e3e3a7aSWarner Losh 
1208e3e3a7aSWarner Losh 
1218e3e3a7aSWarner Losh 
1228e3e3a7aSWarner Losh static void check_match (LexState *ls, int what, int who, int where) {
1238e3e3a7aSWarner Losh   if (!testnext(ls, what)) {
1248e3e3a7aSWarner Losh     if (where == ls->linenumber)
1258e3e3a7aSWarner Losh       error_expected(ls, what);
1268e3e3a7aSWarner Losh     else {
1278e3e3a7aSWarner Losh       luaX_syntaxerror(ls, luaO_pushfstring(ls->L,
1288e3e3a7aSWarner Losh              "%s expected (to close %s at line %d)",
1298e3e3a7aSWarner Losh               luaX_token2str(ls, what), luaX_token2str(ls, who), where));
1308e3e3a7aSWarner Losh     }
1318e3e3a7aSWarner Losh   }
1328e3e3a7aSWarner Losh }
1338e3e3a7aSWarner Losh 
1348e3e3a7aSWarner Losh 
1358e3e3a7aSWarner Losh static TString *str_checkname (LexState *ls) {
1368e3e3a7aSWarner Losh   TString *ts;
1378e3e3a7aSWarner Losh   check(ls, TK_NAME);
1388e3e3a7aSWarner Losh   ts = ls->t.seminfo.ts;
1398e3e3a7aSWarner Losh   luaX_next(ls);
1408e3e3a7aSWarner Losh   return ts;
1418e3e3a7aSWarner Losh }
1428e3e3a7aSWarner Losh 
1438e3e3a7aSWarner Losh 
1448e3e3a7aSWarner Losh static void init_exp (expdesc *e, expkind k, int i) {
1458e3e3a7aSWarner Losh   e->f = e->t = NO_JUMP;
1468e3e3a7aSWarner Losh   e->k = k;
1478e3e3a7aSWarner Losh   e->u.info = i;
1488e3e3a7aSWarner Losh }
1498e3e3a7aSWarner Losh 
1508e3e3a7aSWarner Losh 
1518e3e3a7aSWarner Losh static void codestring (LexState *ls, expdesc *e, TString *s) {
1528e3e3a7aSWarner Losh   init_exp(e, VK, luaK_stringK(ls->fs, s));
1538e3e3a7aSWarner Losh }
1548e3e3a7aSWarner Losh 
1558e3e3a7aSWarner Losh 
1568e3e3a7aSWarner Losh static void checkname (LexState *ls, expdesc *e) {
1578e3e3a7aSWarner Losh   codestring(ls, e, str_checkname(ls));
1588e3e3a7aSWarner Losh }
1598e3e3a7aSWarner Losh 
1608e3e3a7aSWarner Losh 
1618e3e3a7aSWarner Losh static int registerlocalvar (LexState *ls, TString *varname) {
1628e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
1638e3e3a7aSWarner Losh   Proto *f = fs->f;
1648e3e3a7aSWarner Losh   int oldsize = f->sizelocvars;
1658e3e3a7aSWarner Losh   luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
1668e3e3a7aSWarner Losh                   LocVar, SHRT_MAX, "local variables");
1678e3e3a7aSWarner Losh   while (oldsize < f->sizelocvars)
1688e3e3a7aSWarner Losh     f->locvars[oldsize++].varname = NULL;
1698e3e3a7aSWarner Losh   f->locvars[fs->nlocvars].varname = varname;
1708e3e3a7aSWarner Losh   luaC_objbarrier(ls->L, f, varname);
1718e3e3a7aSWarner Losh   return fs->nlocvars++;
1728e3e3a7aSWarner Losh }
1738e3e3a7aSWarner Losh 
1748e3e3a7aSWarner Losh 
1758e3e3a7aSWarner Losh static void new_localvar (LexState *ls, TString *name) {
1768e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
1778e3e3a7aSWarner Losh   Dyndata *dyd = ls->dyd;
1788e3e3a7aSWarner Losh   int reg = registerlocalvar(ls, name);
1798e3e3a7aSWarner Losh   checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
1808e3e3a7aSWarner Losh                   MAXVARS, "local variables");
1818e3e3a7aSWarner Losh   luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1,
1828e3e3a7aSWarner Losh                   dyd->actvar.size, Vardesc, MAX_INT, "local variables");
1838e3e3a7aSWarner Losh   dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);
1848e3e3a7aSWarner Losh }
1858e3e3a7aSWarner Losh 
1868e3e3a7aSWarner Losh 
1878e3e3a7aSWarner Losh static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
1888e3e3a7aSWarner Losh   new_localvar(ls, luaX_newstring(ls, name, sz));
1898e3e3a7aSWarner Losh }
1908e3e3a7aSWarner Losh 
1918e3e3a7aSWarner Losh #define new_localvarliteral(ls,v) \
1928e3e3a7aSWarner Losh 	new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1)
1938e3e3a7aSWarner Losh 
1948e3e3a7aSWarner Losh 
1958e3e3a7aSWarner Losh static LocVar *getlocvar (FuncState *fs, int i) {
1968e3e3a7aSWarner Losh   int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx;
1978e3e3a7aSWarner Losh   lua_assert(idx < fs->nlocvars);
1988e3e3a7aSWarner Losh   return &fs->f->locvars[idx];
1998e3e3a7aSWarner Losh }
2008e3e3a7aSWarner Losh 
2018e3e3a7aSWarner Losh 
2028e3e3a7aSWarner Losh static void adjustlocalvars (LexState *ls, int nvars) {
2038e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
2048e3e3a7aSWarner Losh   fs->nactvar = cast_byte(fs->nactvar + nvars);
2058e3e3a7aSWarner Losh   for (; nvars; nvars--) {
2068e3e3a7aSWarner Losh     getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc;
2078e3e3a7aSWarner Losh   }
2088e3e3a7aSWarner Losh }
2098e3e3a7aSWarner Losh 
2108e3e3a7aSWarner Losh 
2118e3e3a7aSWarner Losh static void removevars (FuncState *fs, int tolevel) {
2128e3e3a7aSWarner Losh   fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
2138e3e3a7aSWarner Losh   while (fs->nactvar > tolevel)
2148e3e3a7aSWarner Losh     getlocvar(fs, --fs->nactvar)->endpc = fs->pc;
2158e3e3a7aSWarner Losh }
2168e3e3a7aSWarner Losh 
2178e3e3a7aSWarner Losh 
2188e3e3a7aSWarner Losh static int searchupvalue (FuncState *fs, TString *name) {
2198e3e3a7aSWarner Losh   int i;
2208e3e3a7aSWarner Losh   Upvaldesc *up = fs->f->upvalues;
2218e3e3a7aSWarner Losh   for (i = 0; i < fs->nups; i++) {
2228e3e3a7aSWarner Losh     if (eqstr(up[i].name, name)) return i;
2238e3e3a7aSWarner Losh   }
2248e3e3a7aSWarner Losh   return -1;  /* not found */
2258e3e3a7aSWarner Losh }
2268e3e3a7aSWarner Losh 
2278e3e3a7aSWarner Losh 
2288e3e3a7aSWarner Losh static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
2298e3e3a7aSWarner Losh   Proto *f = fs->f;
2308e3e3a7aSWarner Losh   int oldsize = f->sizeupvalues;
2318e3e3a7aSWarner Losh   checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
2328e3e3a7aSWarner Losh   luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
2338e3e3a7aSWarner Losh                   Upvaldesc, MAXUPVAL, "upvalues");
2348e3e3a7aSWarner Losh   while (oldsize < f->sizeupvalues)
2358e3e3a7aSWarner Losh     f->upvalues[oldsize++].name = NULL;
2368e3e3a7aSWarner Losh   f->upvalues[fs->nups].instack = (v->k == VLOCAL);
2378e3e3a7aSWarner Losh   f->upvalues[fs->nups].idx = cast_byte(v->u.info);
2388e3e3a7aSWarner Losh   f->upvalues[fs->nups].name = name;
2398e3e3a7aSWarner Losh   luaC_objbarrier(fs->ls->L, f, name);
2408e3e3a7aSWarner Losh   return fs->nups++;
2418e3e3a7aSWarner Losh }
2428e3e3a7aSWarner Losh 
2438e3e3a7aSWarner Losh 
2448e3e3a7aSWarner Losh static int searchvar (FuncState *fs, TString *n) {
2458e3e3a7aSWarner Losh   int i;
2468e3e3a7aSWarner Losh   for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
2478e3e3a7aSWarner Losh     if (eqstr(n, getlocvar(fs, i)->varname))
2488e3e3a7aSWarner Losh       return i;
2498e3e3a7aSWarner Losh   }
2508e3e3a7aSWarner Losh   return -1;  /* not found */
2518e3e3a7aSWarner Losh }
2528e3e3a7aSWarner Losh 
2538e3e3a7aSWarner Losh 
2548e3e3a7aSWarner Losh /*
2558e3e3a7aSWarner Losh   Mark block where variable at given level was defined
2568e3e3a7aSWarner Losh   (to emit close instructions later).
2578e3e3a7aSWarner Losh */
2588e3e3a7aSWarner Losh static void markupval (FuncState *fs, int level) {
2598e3e3a7aSWarner Losh   BlockCnt *bl = fs->bl;
2608e3e3a7aSWarner Losh   while (bl->nactvar > level)
2618e3e3a7aSWarner Losh     bl = bl->previous;
2628e3e3a7aSWarner Losh   bl->upval = 1;
2638e3e3a7aSWarner Losh }
2648e3e3a7aSWarner Losh 
2658e3e3a7aSWarner Losh 
2668e3e3a7aSWarner Losh /*
2678e3e3a7aSWarner Losh   Find variable with given name 'n'. If it is an upvalue, add this
2688e3e3a7aSWarner Losh   upvalue into all intermediate functions.
2698e3e3a7aSWarner Losh */
2708e3e3a7aSWarner Losh static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
2718e3e3a7aSWarner Losh   if (fs == NULL)  /* no more levels? */
2728e3e3a7aSWarner Losh     init_exp(var, VVOID, 0);  /* default is global */
2738e3e3a7aSWarner Losh   else {
2748e3e3a7aSWarner Losh     int v = searchvar(fs, n);  /* look up locals at current level */
2758e3e3a7aSWarner Losh     if (v >= 0) {  /* found? */
2768e3e3a7aSWarner Losh       init_exp(var, VLOCAL, v);  /* variable is local */
2778e3e3a7aSWarner Losh       if (!base)
2788e3e3a7aSWarner Losh         markupval(fs, v);  /* local will be used as an upval */
2798e3e3a7aSWarner Losh     }
2808e3e3a7aSWarner Losh     else {  /* not found as local at current level; try upvalues */
2818e3e3a7aSWarner Losh       int idx = searchupvalue(fs, n);  /* try existing upvalues */
2828e3e3a7aSWarner Losh       if (idx < 0) {  /* not found? */
2838e3e3a7aSWarner Losh         singlevaraux(fs->prev, n, var, 0);  /* try upper levels */
2848e3e3a7aSWarner Losh         if (var->k == VVOID)  /* not found? */
2858e3e3a7aSWarner Losh           return;  /* it is a global */
2868e3e3a7aSWarner Losh         /* else was LOCAL or UPVAL */
2878e3e3a7aSWarner Losh         idx  = newupvalue(fs, n, var);  /* will be a new upvalue */
2888e3e3a7aSWarner Losh       }
2898e3e3a7aSWarner Losh       init_exp(var, VUPVAL, idx);  /* new or old upvalue */
2908e3e3a7aSWarner Losh     }
2918e3e3a7aSWarner Losh   }
2928e3e3a7aSWarner Losh }
2938e3e3a7aSWarner Losh 
2948e3e3a7aSWarner Losh 
2958e3e3a7aSWarner Losh static void singlevar (LexState *ls, expdesc *var) {
2968e3e3a7aSWarner Losh   TString *varname = str_checkname(ls);
2978e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
2988e3e3a7aSWarner Losh   singlevaraux(fs, varname, var, 1);
2998e3e3a7aSWarner Losh   if (var->k == VVOID) {  /* global name? */
3008e3e3a7aSWarner Losh     expdesc key;
3018e3e3a7aSWarner Losh     singlevaraux(fs, ls->envn, var, 1);  /* get environment variable */
3028e3e3a7aSWarner Losh     lua_assert(var->k != VVOID);  /* this one must exist */
3038e3e3a7aSWarner Losh     codestring(ls, &key, varname);  /* key is variable name */
3048e3e3a7aSWarner Losh     luaK_indexed(fs, var, &key);  /* env[varname] */
3058e3e3a7aSWarner Losh   }
3068e3e3a7aSWarner Losh }
3078e3e3a7aSWarner Losh 
3088e3e3a7aSWarner Losh 
3098e3e3a7aSWarner Losh static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
3108e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
3118e3e3a7aSWarner Losh   int extra = nvars - nexps;
3128e3e3a7aSWarner Losh   if (hasmultret(e->k)) {
3138e3e3a7aSWarner Losh     extra++;  /* includes call itself */
3148e3e3a7aSWarner Losh     if (extra < 0) extra = 0;
3158e3e3a7aSWarner Losh     luaK_setreturns(fs, e, extra);  /* last exp. provides the difference */
3168e3e3a7aSWarner Losh     if (extra > 1) luaK_reserveregs(fs, extra-1);
3178e3e3a7aSWarner Losh   }
3188e3e3a7aSWarner Losh   else {
3198e3e3a7aSWarner Losh     if (e->k != VVOID) luaK_exp2nextreg(fs, e);  /* close last expression */
3208e3e3a7aSWarner Losh     if (extra > 0) {
3218e3e3a7aSWarner Losh       int reg = fs->freereg;
3228e3e3a7aSWarner Losh       luaK_reserveregs(fs, extra);
3238e3e3a7aSWarner Losh       luaK_nil(fs, reg, extra);
3248e3e3a7aSWarner Losh     }
3258e3e3a7aSWarner Losh   }
3268e3e3a7aSWarner Losh   if (nexps > nvars)
3278e3e3a7aSWarner Losh     ls->fs->freereg -= nexps - nvars;  /* remove extra values */
3288e3e3a7aSWarner Losh }
3298e3e3a7aSWarner Losh 
3308e3e3a7aSWarner Losh 
3318e3e3a7aSWarner Losh static void enterlevel (LexState *ls) {
3328e3e3a7aSWarner Losh   lua_State *L = ls->L;
3338e3e3a7aSWarner Losh   ++L->nCcalls;
3348e3e3a7aSWarner Losh   checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels");
3358e3e3a7aSWarner Losh }
3368e3e3a7aSWarner Losh 
3378e3e3a7aSWarner Losh 
3388e3e3a7aSWarner Losh #define leavelevel(ls)	((ls)->L->nCcalls--)
3398e3e3a7aSWarner Losh 
3408e3e3a7aSWarner Losh 
3418e3e3a7aSWarner Losh static void closegoto (LexState *ls, int g, Labeldesc *label) {
3428e3e3a7aSWarner Losh   int i;
3438e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
3448e3e3a7aSWarner Losh   Labellist *gl = &ls->dyd->gt;
3458e3e3a7aSWarner Losh   Labeldesc *gt = &gl->arr[g];
3468e3e3a7aSWarner Losh   lua_assert(eqstr(gt->name, label->name));
3478e3e3a7aSWarner Losh   if (gt->nactvar < label->nactvar) {
3488e3e3a7aSWarner Losh     TString *vname = getlocvar(fs, gt->nactvar)->varname;
3498e3e3a7aSWarner Losh     const char *msg = luaO_pushfstring(ls->L,
3508e3e3a7aSWarner Losh       "<goto %s> at line %d jumps into the scope of local '%s'",
3518e3e3a7aSWarner Losh       getstr(gt->name), gt->line, getstr(vname));
3528e3e3a7aSWarner Losh     semerror(ls, msg);
3538e3e3a7aSWarner Losh   }
3548e3e3a7aSWarner Losh   luaK_patchlist(fs, gt->pc, label->pc);
3558e3e3a7aSWarner Losh   /* remove goto from pending list */
3568e3e3a7aSWarner Losh   for (i = g; i < gl->n - 1; i++)
3578e3e3a7aSWarner Losh     gl->arr[i] = gl->arr[i + 1];
3588e3e3a7aSWarner Losh   gl->n--;
3598e3e3a7aSWarner Losh }
3608e3e3a7aSWarner Losh 
3618e3e3a7aSWarner Losh 
3628e3e3a7aSWarner Losh /*
3638e3e3a7aSWarner Losh ** try to close a goto with existing labels; this solves backward jumps
3648e3e3a7aSWarner Losh */
3658e3e3a7aSWarner Losh static int findlabel (LexState *ls, int g) {
3668e3e3a7aSWarner Losh   int i;
3678e3e3a7aSWarner Losh   BlockCnt *bl = ls->fs->bl;
3688e3e3a7aSWarner Losh   Dyndata *dyd = ls->dyd;
3698e3e3a7aSWarner Losh   Labeldesc *gt = &dyd->gt.arr[g];
3708e3e3a7aSWarner Losh   /* check labels in current block for a match */
3718e3e3a7aSWarner Losh   for (i = bl->firstlabel; i < dyd->label.n; i++) {
3728e3e3a7aSWarner Losh     Labeldesc *lb = &dyd->label.arr[i];
3738e3e3a7aSWarner Losh     if (eqstr(lb->name, gt->name)) {  /* correct label? */
3748e3e3a7aSWarner Losh       if (gt->nactvar > lb->nactvar &&
3758e3e3a7aSWarner Losh           (bl->upval || dyd->label.n > bl->firstlabel))
3768e3e3a7aSWarner Losh         luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
3778e3e3a7aSWarner Losh       closegoto(ls, g, lb);  /* close it */
3788e3e3a7aSWarner Losh       return 1;
3798e3e3a7aSWarner Losh     }
3808e3e3a7aSWarner Losh   }
3818e3e3a7aSWarner Losh   return 0;  /* label not found; cannot close goto */
3828e3e3a7aSWarner Losh }
3838e3e3a7aSWarner Losh 
3848e3e3a7aSWarner Losh 
3858e3e3a7aSWarner Losh static int newlabelentry (LexState *ls, Labellist *l, TString *name,
3868e3e3a7aSWarner Losh                           int line, int pc) {
3878e3e3a7aSWarner Losh   int n = l->n;
3888e3e3a7aSWarner Losh   luaM_growvector(ls->L, l->arr, n, l->size,
3898e3e3a7aSWarner Losh                   Labeldesc, SHRT_MAX, "labels/gotos");
3908e3e3a7aSWarner Losh   l->arr[n].name = name;
3918e3e3a7aSWarner Losh   l->arr[n].line = line;
3928e3e3a7aSWarner Losh   l->arr[n].nactvar = ls->fs->nactvar;
3938e3e3a7aSWarner Losh   l->arr[n].pc = pc;
3948e3e3a7aSWarner Losh   l->n = n + 1;
3958e3e3a7aSWarner Losh   return n;
3968e3e3a7aSWarner Losh }
3978e3e3a7aSWarner Losh 
3988e3e3a7aSWarner Losh 
3998e3e3a7aSWarner Losh /*
4008e3e3a7aSWarner Losh ** check whether new label 'lb' matches any pending gotos in current
4018e3e3a7aSWarner Losh ** block; solves forward jumps
4028e3e3a7aSWarner Losh */
4038e3e3a7aSWarner Losh static void findgotos (LexState *ls, Labeldesc *lb) {
4048e3e3a7aSWarner Losh   Labellist *gl = &ls->dyd->gt;
4058e3e3a7aSWarner Losh   int i = ls->fs->bl->firstgoto;
4068e3e3a7aSWarner Losh   while (i < gl->n) {
4078e3e3a7aSWarner Losh     if (eqstr(gl->arr[i].name, lb->name))
4088e3e3a7aSWarner Losh       closegoto(ls, i, lb);
4098e3e3a7aSWarner Losh     else
4108e3e3a7aSWarner Losh       i++;
4118e3e3a7aSWarner Losh   }
4128e3e3a7aSWarner Losh }
4138e3e3a7aSWarner Losh 
4148e3e3a7aSWarner Losh 
4158e3e3a7aSWarner Losh /*
4168e3e3a7aSWarner Losh ** export pending gotos to outer level, to check them against
4178e3e3a7aSWarner Losh ** outer labels; if the block being exited has upvalues, and
4188e3e3a7aSWarner Losh ** the goto exits the scope of any variable (which can be the
4198e3e3a7aSWarner Losh ** upvalue), close those variables being exited.
4208e3e3a7aSWarner Losh */
4218e3e3a7aSWarner Losh static void movegotosout (FuncState *fs, BlockCnt *bl) {
4228e3e3a7aSWarner Losh   int i = bl->firstgoto;
4238e3e3a7aSWarner Losh   Labellist *gl = &fs->ls->dyd->gt;
4248e3e3a7aSWarner Losh   /* correct pending gotos to current block and try to close it
4258e3e3a7aSWarner Losh      with visible labels */
4268e3e3a7aSWarner Losh   while (i < gl->n) {
4278e3e3a7aSWarner Losh     Labeldesc *gt = &gl->arr[i];
4288e3e3a7aSWarner Losh     if (gt->nactvar > bl->nactvar) {
4298e3e3a7aSWarner Losh       if (bl->upval)
4308e3e3a7aSWarner Losh         luaK_patchclose(fs, gt->pc, bl->nactvar);
4318e3e3a7aSWarner Losh       gt->nactvar = bl->nactvar;
4328e3e3a7aSWarner Losh     }
4338e3e3a7aSWarner Losh     if (!findlabel(fs->ls, i))
4348e3e3a7aSWarner Losh       i++;  /* move to next one */
4358e3e3a7aSWarner Losh   }
4368e3e3a7aSWarner Losh }
4378e3e3a7aSWarner Losh 
4388e3e3a7aSWarner Losh 
4398e3e3a7aSWarner Losh static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) {
4408e3e3a7aSWarner Losh   bl->isloop = isloop;
4418e3e3a7aSWarner Losh   bl->nactvar = fs->nactvar;
4428e3e3a7aSWarner Losh   bl->firstlabel = fs->ls->dyd->label.n;
4438e3e3a7aSWarner Losh   bl->firstgoto = fs->ls->dyd->gt.n;
4448e3e3a7aSWarner Losh   bl->upval = 0;
4458e3e3a7aSWarner Losh   bl->previous = fs->bl;
4468e3e3a7aSWarner Losh   fs->bl = bl;
4478e3e3a7aSWarner Losh   lua_assert(fs->freereg == fs->nactvar);
4488e3e3a7aSWarner Losh }
4498e3e3a7aSWarner Losh 
4508e3e3a7aSWarner Losh 
4518e3e3a7aSWarner Losh /*
4528e3e3a7aSWarner Losh ** create a label named 'break' to resolve break statements
4538e3e3a7aSWarner Losh */
4548e3e3a7aSWarner Losh static void breaklabel (LexState *ls) {
4558e3e3a7aSWarner Losh   TString *n = luaS_new(ls->L, "break");
4568e3e3a7aSWarner Losh   int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc);
4578e3e3a7aSWarner Losh   findgotos(ls, &ls->dyd->label.arr[l]);
4588e3e3a7aSWarner Losh }
4598e3e3a7aSWarner Losh 
4608e3e3a7aSWarner Losh /*
4618e3e3a7aSWarner Losh ** generates an error for an undefined 'goto'; choose appropriate
4628e3e3a7aSWarner Losh ** message when label name is a reserved word (which can only be 'break')
4638e3e3a7aSWarner Losh */
4648e3e3a7aSWarner Losh static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
4658e3e3a7aSWarner Losh   const char *msg = isreserved(gt->name)
4668e3e3a7aSWarner Losh                     ? "<%s> at line %d not inside a loop"
4678e3e3a7aSWarner Losh                     : "no visible label '%s' for <goto> at line %d";
4688e3e3a7aSWarner Losh   msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
4698e3e3a7aSWarner Losh   semerror(ls, msg);
4708e3e3a7aSWarner Losh }
4718e3e3a7aSWarner Losh 
4728e3e3a7aSWarner Losh 
4738e3e3a7aSWarner Losh static void leaveblock (FuncState *fs) {
4748e3e3a7aSWarner Losh   BlockCnt *bl = fs->bl;
4758e3e3a7aSWarner Losh   LexState *ls = fs->ls;
4768e3e3a7aSWarner Losh   if (bl->previous && bl->upval) {
4778e3e3a7aSWarner Losh     /* create a 'jump to here' to close upvalues */
4788e3e3a7aSWarner Losh     int j = luaK_jump(fs);
4798e3e3a7aSWarner Losh     luaK_patchclose(fs, j, bl->nactvar);
4808e3e3a7aSWarner Losh     luaK_patchtohere(fs, j);
4818e3e3a7aSWarner Losh   }
4828e3e3a7aSWarner Losh   if (bl->isloop)
4838e3e3a7aSWarner Losh     breaklabel(ls);  /* close pending breaks */
4848e3e3a7aSWarner Losh   fs->bl = bl->previous;
4858e3e3a7aSWarner Losh   removevars(fs, bl->nactvar);
4868e3e3a7aSWarner Losh   lua_assert(bl->nactvar == fs->nactvar);
4878e3e3a7aSWarner Losh   fs->freereg = fs->nactvar;  /* free registers */
4888e3e3a7aSWarner Losh   ls->dyd->label.n = bl->firstlabel;  /* remove local labels */
4898e3e3a7aSWarner Losh   if (bl->previous)  /* inner block? */
4908e3e3a7aSWarner Losh     movegotosout(fs, bl);  /* update pending gotos to outer block */
4918e3e3a7aSWarner Losh   else if (bl->firstgoto < ls->dyd->gt.n)  /* pending gotos in outer block? */
4928e3e3a7aSWarner Losh     undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]);  /* error */
4938e3e3a7aSWarner Losh }
4948e3e3a7aSWarner Losh 
4958e3e3a7aSWarner Losh 
4968e3e3a7aSWarner Losh /*
4978e3e3a7aSWarner Losh ** adds a new prototype into list of prototypes
4988e3e3a7aSWarner Losh */
4998e3e3a7aSWarner Losh static Proto *addprototype (LexState *ls) {
5008e3e3a7aSWarner Losh   Proto *clp;
5018e3e3a7aSWarner Losh   lua_State *L = ls->L;
5028e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
5038e3e3a7aSWarner Losh   Proto *f = fs->f;  /* prototype of current function */
5048e3e3a7aSWarner Losh   if (fs->np >= f->sizep) {
5058e3e3a7aSWarner Losh     int oldsize = f->sizep;
5068e3e3a7aSWarner Losh     luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
5078e3e3a7aSWarner Losh     while (oldsize < f->sizep)
5088e3e3a7aSWarner Losh       f->p[oldsize++] = NULL;
5098e3e3a7aSWarner Losh   }
5108e3e3a7aSWarner Losh   f->p[fs->np++] = clp = luaF_newproto(L);
5118e3e3a7aSWarner Losh   luaC_objbarrier(L, f, clp);
5128e3e3a7aSWarner Losh   return clp;
5138e3e3a7aSWarner Losh }
5148e3e3a7aSWarner Losh 
5158e3e3a7aSWarner Losh 
5168e3e3a7aSWarner Losh /*
5178e3e3a7aSWarner Losh ** codes instruction to create new closure in parent function.
5188e3e3a7aSWarner Losh ** The OP_CLOSURE instruction must use the last available register,
5198e3e3a7aSWarner Losh ** so that, if it invokes the GC, the GC knows which registers
5208e3e3a7aSWarner Losh ** are in use at that time.
5218e3e3a7aSWarner Losh */
5228e3e3a7aSWarner Losh static void codeclosure (LexState *ls, expdesc *v) {
5238e3e3a7aSWarner Losh   FuncState *fs = ls->fs->prev;
5248e3e3a7aSWarner Losh   init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));
5258e3e3a7aSWarner Losh   luaK_exp2nextreg(fs, v);  /* fix it at the last register */
5268e3e3a7aSWarner Losh }
5278e3e3a7aSWarner Losh 
5288e3e3a7aSWarner Losh 
5298e3e3a7aSWarner Losh static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
5308e3e3a7aSWarner Losh   Proto *f;
5318e3e3a7aSWarner Losh   fs->prev = ls->fs;  /* linked list of funcstates */
5328e3e3a7aSWarner Losh   fs->ls = ls;
5338e3e3a7aSWarner Losh   ls->fs = fs;
5348e3e3a7aSWarner Losh   fs->pc = 0;
5358e3e3a7aSWarner Losh   fs->lasttarget = 0;
5368e3e3a7aSWarner Losh   fs->jpc = NO_JUMP;
5378e3e3a7aSWarner Losh   fs->freereg = 0;
5388e3e3a7aSWarner Losh   fs->nk = 0;
5398e3e3a7aSWarner Losh   fs->np = 0;
5408e3e3a7aSWarner Losh   fs->nups = 0;
5418e3e3a7aSWarner Losh   fs->nlocvars = 0;
5428e3e3a7aSWarner Losh   fs->nactvar = 0;
5438e3e3a7aSWarner Losh   fs->firstlocal = ls->dyd->actvar.n;
5448e3e3a7aSWarner Losh   fs->bl = NULL;
5458e3e3a7aSWarner Losh   f = fs->f;
5468e3e3a7aSWarner Losh   f->source = ls->source;
547*bf9580a1SKyle Evans   luaC_objbarrier(ls->L, f, f->source);
5488e3e3a7aSWarner Losh   f->maxstacksize = 2;  /* registers 0/1 are always valid */
5498e3e3a7aSWarner Losh   enterblock(fs, bl, 0);
5508e3e3a7aSWarner Losh }
5518e3e3a7aSWarner Losh 
5528e3e3a7aSWarner Losh 
5538e3e3a7aSWarner Losh static void close_func (LexState *ls) {
5548e3e3a7aSWarner Losh   lua_State *L = ls->L;
5558e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
5568e3e3a7aSWarner Losh   Proto *f = fs->f;
5578e3e3a7aSWarner Losh   luaK_ret(fs, 0, 0);  /* final return */
5588e3e3a7aSWarner Losh   leaveblock(fs);
5598e3e3a7aSWarner Losh   luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
5608e3e3a7aSWarner Losh   f->sizecode = fs->pc;
5618e3e3a7aSWarner Losh   luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
5628e3e3a7aSWarner Losh   f->sizelineinfo = fs->pc;
5638e3e3a7aSWarner Losh   luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue);
5648e3e3a7aSWarner Losh   f->sizek = fs->nk;
5658e3e3a7aSWarner Losh   luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *);
5668e3e3a7aSWarner Losh   f->sizep = fs->np;
5678e3e3a7aSWarner Losh   luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
5688e3e3a7aSWarner Losh   f->sizelocvars = fs->nlocvars;
5698e3e3a7aSWarner Losh   luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
5708e3e3a7aSWarner Losh   f->sizeupvalues = fs->nups;
5718e3e3a7aSWarner Losh   lua_assert(fs->bl == NULL);
5728e3e3a7aSWarner Losh   ls->fs = fs->prev;
5738e3e3a7aSWarner Losh   luaC_checkGC(L);
5748e3e3a7aSWarner Losh }
5758e3e3a7aSWarner Losh 
5768e3e3a7aSWarner Losh 
5778e3e3a7aSWarner Losh 
5788e3e3a7aSWarner Losh /*============================================================*/
5798e3e3a7aSWarner Losh /* GRAMMAR RULES */
5808e3e3a7aSWarner Losh /*============================================================*/
5818e3e3a7aSWarner Losh 
5828e3e3a7aSWarner Losh 
5838e3e3a7aSWarner Losh /*
5848e3e3a7aSWarner Losh ** check whether current token is in the follow set of a block.
5858e3e3a7aSWarner Losh ** 'until' closes syntactical blocks, but do not close scope,
5868e3e3a7aSWarner Losh ** so it is handled in separate.
5878e3e3a7aSWarner Losh */
5888e3e3a7aSWarner Losh static int block_follow (LexState *ls, int withuntil) {
5898e3e3a7aSWarner Losh   switch (ls->t.token) {
5908e3e3a7aSWarner Losh     case TK_ELSE: case TK_ELSEIF:
5918e3e3a7aSWarner Losh     case TK_END: case TK_EOS:
5928e3e3a7aSWarner Losh       return 1;
5938e3e3a7aSWarner Losh     case TK_UNTIL: return withuntil;
5948e3e3a7aSWarner Losh     default: return 0;
5958e3e3a7aSWarner Losh   }
5968e3e3a7aSWarner Losh }
5978e3e3a7aSWarner Losh 
5988e3e3a7aSWarner Losh 
5998e3e3a7aSWarner Losh static void statlist (LexState *ls) {
6008e3e3a7aSWarner Losh   /* statlist -> { stat [';'] } */
6018e3e3a7aSWarner Losh   while (!block_follow(ls, 1)) {
6028e3e3a7aSWarner Losh     if (ls->t.token == TK_RETURN) {
6038e3e3a7aSWarner Losh       statement(ls);
6048e3e3a7aSWarner Losh       return;  /* 'return' must be last statement */
6058e3e3a7aSWarner Losh     }
6068e3e3a7aSWarner Losh     statement(ls);
6078e3e3a7aSWarner Losh   }
6088e3e3a7aSWarner Losh }
6098e3e3a7aSWarner Losh 
6108e3e3a7aSWarner Losh 
6118e3e3a7aSWarner Losh static void fieldsel (LexState *ls, expdesc *v) {
6128e3e3a7aSWarner Losh   /* fieldsel -> ['.' | ':'] NAME */
6138e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
6148e3e3a7aSWarner Losh   expdesc key;
6158e3e3a7aSWarner Losh   luaK_exp2anyregup(fs, v);
6168e3e3a7aSWarner Losh   luaX_next(ls);  /* skip the dot or colon */
6178e3e3a7aSWarner Losh   checkname(ls, &key);
6188e3e3a7aSWarner Losh   luaK_indexed(fs, v, &key);
6198e3e3a7aSWarner Losh }
6208e3e3a7aSWarner Losh 
6218e3e3a7aSWarner Losh 
6228e3e3a7aSWarner Losh static void yindex (LexState *ls, expdesc *v) {
6238e3e3a7aSWarner Losh   /* index -> '[' expr ']' */
6248e3e3a7aSWarner Losh   luaX_next(ls);  /* skip the '[' */
6258e3e3a7aSWarner Losh   expr(ls, v);
6268e3e3a7aSWarner Losh   luaK_exp2val(ls->fs, v);
6278e3e3a7aSWarner Losh   checknext(ls, ']');
6288e3e3a7aSWarner Losh }
6298e3e3a7aSWarner Losh 
6308e3e3a7aSWarner Losh 
6318e3e3a7aSWarner Losh /*
6328e3e3a7aSWarner Losh ** {======================================================================
6338e3e3a7aSWarner Losh ** Rules for Constructors
6348e3e3a7aSWarner Losh ** =======================================================================
6358e3e3a7aSWarner Losh */
6368e3e3a7aSWarner Losh 
6378e3e3a7aSWarner Losh 
6388e3e3a7aSWarner Losh struct ConsControl {
6398e3e3a7aSWarner Losh   expdesc v;  /* last list item read */
6408e3e3a7aSWarner Losh   expdesc *t;  /* table descriptor */
6418e3e3a7aSWarner Losh   int nh;  /* total number of 'record' elements */
6428e3e3a7aSWarner Losh   int na;  /* total number of array elements */
6438e3e3a7aSWarner Losh   int tostore;  /* number of array elements pending to be stored */
6448e3e3a7aSWarner Losh };
6458e3e3a7aSWarner Losh 
6468e3e3a7aSWarner Losh 
6478e3e3a7aSWarner Losh static void recfield (LexState *ls, struct ConsControl *cc) {
6488e3e3a7aSWarner Losh   /* recfield -> (NAME | '['exp1']') = exp1 */
6498e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
6508e3e3a7aSWarner Losh   int reg = ls->fs->freereg;
6518e3e3a7aSWarner Losh   expdesc key, val;
6528e3e3a7aSWarner Losh   int rkkey;
6538e3e3a7aSWarner Losh   if (ls->t.token == TK_NAME) {
6548e3e3a7aSWarner Losh     checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
6558e3e3a7aSWarner Losh     checkname(ls, &key);
6568e3e3a7aSWarner Losh   }
6578e3e3a7aSWarner Losh   else  /* ls->t.token == '[' */
6588e3e3a7aSWarner Losh     yindex(ls, &key);
6598e3e3a7aSWarner Losh   cc->nh++;
6608e3e3a7aSWarner Losh   checknext(ls, '=');
6618e3e3a7aSWarner Losh   rkkey = luaK_exp2RK(fs, &key);
6628e3e3a7aSWarner Losh   expr(ls, &val);
6638e3e3a7aSWarner Losh   luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val));
6648e3e3a7aSWarner Losh   fs->freereg = reg;  /* free registers */
6658e3e3a7aSWarner Losh }
6668e3e3a7aSWarner Losh 
6678e3e3a7aSWarner Losh 
6688e3e3a7aSWarner Losh static void closelistfield (FuncState *fs, struct ConsControl *cc) {
6698e3e3a7aSWarner Losh   if (cc->v.k == VVOID) return;  /* there is no list item */
6708e3e3a7aSWarner Losh   luaK_exp2nextreg(fs, &cc->v);
6718e3e3a7aSWarner Losh   cc->v.k = VVOID;
6728e3e3a7aSWarner Losh   if (cc->tostore == LFIELDS_PER_FLUSH) {
6738e3e3a7aSWarner Losh     luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);  /* flush */
6748e3e3a7aSWarner Losh     cc->tostore = 0;  /* no more items pending */
6758e3e3a7aSWarner Losh   }
6768e3e3a7aSWarner Losh }
6778e3e3a7aSWarner Losh 
6788e3e3a7aSWarner Losh 
6798e3e3a7aSWarner Losh static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
6808e3e3a7aSWarner Losh   if (cc->tostore == 0) return;
6818e3e3a7aSWarner Losh   if (hasmultret(cc->v.k)) {
6828e3e3a7aSWarner Losh     luaK_setmultret(fs, &cc->v);
6838e3e3a7aSWarner Losh     luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET);
6848e3e3a7aSWarner Losh     cc->na--;  /* do not count last expression (unknown number of elements) */
6858e3e3a7aSWarner Losh   }
6868e3e3a7aSWarner Losh   else {
6878e3e3a7aSWarner Losh     if (cc->v.k != VVOID)
6888e3e3a7aSWarner Losh       luaK_exp2nextreg(fs, &cc->v);
6898e3e3a7aSWarner Losh     luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore);
6908e3e3a7aSWarner Losh   }
6918e3e3a7aSWarner Losh }
6928e3e3a7aSWarner Losh 
6938e3e3a7aSWarner Losh 
6948e3e3a7aSWarner Losh static void listfield (LexState *ls, struct ConsControl *cc) {
6958e3e3a7aSWarner Losh   /* listfield -> exp */
6968e3e3a7aSWarner Losh   expr(ls, &cc->v);
6978e3e3a7aSWarner Losh   checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
6988e3e3a7aSWarner Losh   cc->na++;
6998e3e3a7aSWarner Losh   cc->tostore++;
7008e3e3a7aSWarner Losh }
7018e3e3a7aSWarner Losh 
7028e3e3a7aSWarner Losh 
7038e3e3a7aSWarner Losh static void field (LexState *ls, struct ConsControl *cc) {
7048e3e3a7aSWarner Losh   /* field -> listfield | recfield */
7058e3e3a7aSWarner Losh   switch(ls->t.token) {
7068e3e3a7aSWarner Losh     case TK_NAME: {  /* may be 'listfield' or 'recfield' */
7078e3e3a7aSWarner Losh       if (luaX_lookahead(ls) != '=')  /* expression? */
7088e3e3a7aSWarner Losh         listfield(ls, cc);
7098e3e3a7aSWarner Losh       else
7108e3e3a7aSWarner Losh         recfield(ls, cc);
7118e3e3a7aSWarner Losh       break;
7128e3e3a7aSWarner Losh     }
7138e3e3a7aSWarner Losh     case '[': {
7148e3e3a7aSWarner Losh       recfield(ls, cc);
7158e3e3a7aSWarner Losh       break;
7168e3e3a7aSWarner Losh     }
7178e3e3a7aSWarner Losh     default: {
7188e3e3a7aSWarner Losh       listfield(ls, cc);
7198e3e3a7aSWarner Losh       break;
7208e3e3a7aSWarner Losh     }
7218e3e3a7aSWarner Losh   }
7228e3e3a7aSWarner Losh }
7238e3e3a7aSWarner Losh 
7248e3e3a7aSWarner Losh 
7258e3e3a7aSWarner Losh static void constructor (LexState *ls, expdesc *t) {
7268e3e3a7aSWarner Losh   /* constructor -> '{' [ field { sep field } [sep] ] '}'
7278e3e3a7aSWarner Losh      sep -> ',' | ';' */
7288e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
7298e3e3a7aSWarner Losh   int line = ls->linenumber;
7308e3e3a7aSWarner Losh   int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
7318e3e3a7aSWarner Losh   struct ConsControl cc;
7328e3e3a7aSWarner Losh   cc.na = cc.nh = cc.tostore = 0;
7338e3e3a7aSWarner Losh   cc.t = t;
7348e3e3a7aSWarner Losh   init_exp(t, VRELOCABLE, pc);
7358e3e3a7aSWarner Losh   init_exp(&cc.v, VVOID, 0);  /* no value (yet) */
7368e3e3a7aSWarner Losh   luaK_exp2nextreg(ls->fs, t);  /* fix it at stack top */
7378e3e3a7aSWarner Losh   checknext(ls, '{');
7388e3e3a7aSWarner Losh   do {
7398e3e3a7aSWarner Losh     lua_assert(cc.v.k == VVOID || cc.tostore > 0);
7408e3e3a7aSWarner Losh     if (ls->t.token == '}') break;
7418e3e3a7aSWarner Losh     closelistfield(fs, &cc);
7428e3e3a7aSWarner Losh     field(ls, &cc);
7438e3e3a7aSWarner Losh   } while (testnext(ls, ',') || testnext(ls, ';'));
7448e3e3a7aSWarner Losh   check_match(ls, '}', '{', line);
7458e3e3a7aSWarner Losh   lastlistfield(fs, &cc);
7468e3e3a7aSWarner Losh   SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
7478e3e3a7aSWarner Losh   SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh));  /* set initial table size */
7488e3e3a7aSWarner Losh }
7498e3e3a7aSWarner Losh 
7508e3e3a7aSWarner Losh /* }====================================================================== */
7518e3e3a7aSWarner Losh 
7528e3e3a7aSWarner Losh 
7538e3e3a7aSWarner Losh 
7548e3e3a7aSWarner Losh static void parlist (LexState *ls) {
7558e3e3a7aSWarner Losh   /* parlist -> [ param { ',' param } ] */
7568e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
7578e3e3a7aSWarner Losh   Proto *f = fs->f;
7588e3e3a7aSWarner Losh   int nparams = 0;
7598e3e3a7aSWarner Losh   f->is_vararg = 0;
7608e3e3a7aSWarner Losh   if (ls->t.token != ')') {  /* is 'parlist' not empty? */
7618e3e3a7aSWarner Losh     do {
7628e3e3a7aSWarner Losh       switch (ls->t.token) {
7638e3e3a7aSWarner Losh         case TK_NAME: {  /* param -> NAME */
7648e3e3a7aSWarner Losh           new_localvar(ls, str_checkname(ls));
7658e3e3a7aSWarner Losh           nparams++;
7668e3e3a7aSWarner Losh           break;
7678e3e3a7aSWarner Losh         }
7688e3e3a7aSWarner Losh         case TK_DOTS: {  /* param -> '...' */
7698e3e3a7aSWarner Losh           luaX_next(ls);
7708e3e3a7aSWarner Losh           f->is_vararg = 1;  /* declared vararg */
7718e3e3a7aSWarner Losh           break;
7728e3e3a7aSWarner Losh         }
7738e3e3a7aSWarner Losh         default: luaX_syntaxerror(ls, "<name> or '...' expected");
7748e3e3a7aSWarner Losh       }
7758e3e3a7aSWarner Losh     } while (!f->is_vararg && testnext(ls, ','));
7768e3e3a7aSWarner Losh   }
7778e3e3a7aSWarner Losh   adjustlocalvars(ls, nparams);
7788e3e3a7aSWarner Losh   f->numparams = cast_byte(fs->nactvar);
7798e3e3a7aSWarner Losh   luaK_reserveregs(fs, fs->nactvar);  /* reserve register for parameters */
7808e3e3a7aSWarner Losh }
7818e3e3a7aSWarner Losh 
7828e3e3a7aSWarner Losh 
7838e3e3a7aSWarner Losh static void body (LexState *ls, expdesc *e, int ismethod, int line) {
7848e3e3a7aSWarner Losh   /* body ->  '(' parlist ')' block END */
7858e3e3a7aSWarner Losh   FuncState new_fs;
7868e3e3a7aSWarner Losh   BlockCnt bl;
7878e3e3a7aSWarner Losh   new_fs.f = addprototype(ls);
7888e3e3a7aSWarner Losh   new_fs.f->linedefined = line;
7898e3e3a7aSWarner Losh   open_func(ls, &new_fs, &bl);
7908e3e3a7aSWarner Losh   checknext(ls, '(');
7918e3e3a7aSWarner Losh   if (ismethod) {
7928e3e3a7aSWarner Losh     new_localvarliteral(ls, "self");  /* create 'self' parameter */
7938e3e3a7aSWarner Losh     adjustlocalvars(ls, 1);
7948e3e3a7aSWarner Losh   }
7958e3e3a7aSWarner Losh   parlist(ls);
7968e3e3a7aSWarner Losh   checknext(ls, ')');
7978e3e3a7aSWarner Losh   statlist(ls);
7988e3e3a7aSWarner Losh   new_fs.f->lastlinedefined = ls->linenumber;
7998e3e3a7aSWarner Losh   check_match(ls, TK_END, TK_FUNCTION, line);
8008e3e3a7aSWarner Losh   codeclosure(ls, e);
8018e3e3a7aSWarner Losh   close_func(ls);
8028e3e3a7aSWarner Losh }
8038e3e3a7aSWarner Losh 
8048e3e3a7aSWarner Losh 
8058e3e3a7aSWarner Losh static int explist (LexState *ls, expdesc *v) {
8068e3e3a7aSWarner Losh   /* explist -> expr { ',' expr } */
8078e3e3a7aSWarner Losh   int n = 1;  /* at least one expression */
8088e3e3a7aSWarner Losh   expr(ls, v);
8098e3e3a7aSWarner Losh   while (testnext(ls, ',')) {
8108e3e3a7aSWarner Losh     luaK_exp2nextreg(ls->fs, v);
8118e3e3a7aSWarner Losh     expr(ls, v);
8128e3e3a7aSWarner Losh     n++;
8138e3e3a7aSWarner Losh   }
8148e3e3a7aSWarner Losh   return n;
8158e3e3a7aSWarner Losh }
8168e3e3a7aSWarner Losh 
8178e3e3a7aSWarner Losh 
8188e3e3a7aSWarner Losh static void funcargs (LexState *ls, expdesc *f, int line) {
8198e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
8208e3e3a7aSWarner Losh   expdesc args;
8218e3e3a7aSWarner Losh   int base, nparams;
8228e3e3a7aSWarner Losh   switch (ls->t.token) {
8238e3e3a7aSWarner Losh     case '(': {  /* funcargs -> '(' [ explist ] ')' */
8248e3e3a7aSWarner Losh       luaX_next(ls);
8258e3e3a7aSWarner Losh       if (ls->t.token == ')')  /* arg list is empty? */
8268e3e3a7aSWarner Losh         args.k = VVOID;
8278e3e3a7aSWarner Losh       else {
8288e3e3a7aSWarner Losh         explist(ls, &args);
8298e3e3a7aSWarner Losh         luaK_setmultret(fs, &args);
8308e3e3a7aSWarner Losh       }
8318e3e3a7aSWarner Losh       check_match(ls, ')', '(', line);
8328e3e3a7aSWarner Losh       break;
8338e3e3a7aSWarner Losh     }
8348e3e3a7aSWarner Losh     case '{': {  /* funcargs -> constructor */
8358e3e3a7aSWarner Losh       constructor(ls, &args);
8368e3e3a7aSWarner Losh       break;
8378e3e3a7aSWarner Losh     }
8388e3e3a7aSWarner Losh     case TK_STRING: {  /* funcargs -> STRING */
8398e3e3a7aSWarner Losh       codestring(ls, &args, ls->t.seminfo.ts);
8408e3e3a7aSWarner Losh       luaX_next(ls);  /* must use 'seminfo' before 'next' */
8418e3e3a7aSWarner Losh       break;
8428e3e3a7aSWarner Losh     }
8438e3e3a7aSWarner Losh     default: {
8448e3e3a7aSWarner Losh       luaX_syntaxerror(ls, "function arguments expected");
8458e3e3a7aSWarner Losh     }
8468e3e3a7aSWarner Losh   }
8478e3e3a7aSWarner Losh   lua_assert(f->k == VNONRELOC);
8488e3e3a7aSWarner Losh   base = f->u.info;  /* base register for call */
8498e3e3a7aSWarner Losh   if (hasmultret(args.k))
8508e3e3a7aSWarner Losh     nparams = LUA_MULTRET;  /* open call */
8518e3e3a7aSWarner Losh   else {
8528e3e3a7aSWarner Losh     if (args.k != VVOID)
8538e3e3a7aSWarner Losh       luaK_exp2nextreg(fs, &args);  /* close last argument */
8548e3e3a7aSWarner Losh     nparams = fs->freereg - (base+1);
8558e3e3a7aSWarner Losh   }
8568e3e3a7aSWarner Losh   init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
8578e3e3a7aSWarner Losh   luaK_fixline(fs, line);
8588e3e3a7aSWarner Losh   fs->freereg = base+1;  /* call remove function and arguments and leaves
8598e3e3a7aSWarner Losh                             (unless changed) one result */
8608e3e3a7aSWarner Losh }
8618e3e3a7aSWarner Losh 
8628e3e3a7aSWarner Losh 
8638e3e3a7aSWarner Losh 
8648e3e3a7aSWarner Losh 
8658e3e3a7aSWarner Losh /*
8668e3e3a7aSWarner Losh ** {======================================================================
8678e3e3a7aSWarner Losh ** Expression parsing
8688e3e3a7aSWarner Losh ** =======================================================================
8698e3e3a7aSWarner Losh */
8708e3e3a7aSWarner Losh 
8718e3e3a7aSWarner Losh 
8728e3e3a7aSWarner Losh static void primaryexp (LexState *ls, expdesc *v) {
8738e3e3a7aSWarner Losh   /* primaryexp -> NAME | '(' expr ')' */
8748e3e3a7aSWarner Losh   switch (ls->t.token) {
8758e3e3a7aSWarner Losh     case '(': {
8768e3e3a7aSWarner Losh       int line = ls->linenumber;
8778e3e3a7aSWarner Losh       luaX_next(ls);
8788e3e3a7aSWarner Losh       expr(ls, v);
8798e3e3a7aSWarner Losh       check_match(ls, ')', '(', line);
8808e3e3a7aSWarner Losh       luaK_dischargevars(ls->fs, v);
8818e3e3a7aSWarner Losh       return;
8828e3e3a7aSWarner Losh     }
8838e3e3a7aSWarner Losh     case TK_NAME: {
8848e3e3a7aSWarner Losh       singlevar(ls, v);
8858e3e3a7aSWarner Losh       return;
8868e3e3a7aSWarner Losh     }
8878e3e3a7aSWarner Losh     default: {
8888e3e3a7aSWarner Losh       luaX_syntaxerror(ls, "unexpected symbol");
8898e3e3a7aSWarner Losh     }
8908e3e3a7aSWarner Losh   }
8918e3e3a7aSWarner Losh }
8928e3e3a7aSWarner Losh 
8938e3e3a7aSWarner Losh 
8948e3e3a7aSWarner Losh static void suffixedexp (LexState *ls, expdesc *v) {
8958e3e3a7aSWarner Losh   /* suffixedexp ->
8968e3e3a7aSWarner Losh        primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
8978e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
8988e3e3a7aSWarner Losh   int line = ls->linenumber;
8998e3e3a7aSWarner Losh   primaryexp(ls, v);
9008e3e3a7aSWarner Losh   for (;;) {
9018e3e3a7aSWarner Losh     switch (ls->t.token) {
9028e3e3a7aSWarner Losh       case '.': {  /* fieldsel */
9038e3e3a7aSWarner Losh         fieldsel(ls, v);
9048e3e3a7aSWarner Losh         break;
9058e3e3a7aSWarner Losh       }
9068e3e3a7aSWarner Losh       case '[': {  /* '[' exp1 ']' */
9078e3e3a7aSWarner Losh         expdesc key;
9088e3e3a7aSWarner Losh         luaK_exp2anyregup(fs, v);
9098e3e3a7aSWarner Losh         yindex(ls, &key);
9108e3e3a7aSWarner Losh         luaK_indexed(fs, v, &key);
9118e3e3a7aSWarner Losh         break;
9128e3e3a7aSWarner Losh       }
9138e3e3a7aSWarner Losh       case ':': {  /* ':' NAME funcargs */
9148e3e3a7aSWarner Losh         expdesc key;
9158e3e3a7aSWarner Losh         luaX_next(ls);
9168e3e3a7aSWarner Losh         checkname(ls, &key);
9178e3e3a7aSWarner Losh         luaK_self(fs, v, &key);
9188e3e3a7aSWarner Losh         funcargs(ls, v, line);
9198e3e3a7aSWarner Losh         break;
9208e3e3a7aSWarner Losh       }
9218e3e3a7aSWarner Losh       case '(': case TK_STRING: case '{': {  /* funcargs */
9228e3e3a7aSWarner Losh         luaK_exp2nextreg(fs, v);
9238e3e3a7aSWarner Losh         funcargs(ls, v, line);
9248e3e3a7aSWarner Losh         break;
9258e3e3a7aSWarner Losh       }
9268e3e3a7aSWarner Losh       default: return;
9278e3e3a7aSWarner Losh     }
9288e3e3a7aSWarner Losh   }
9298e3e3a7aSWarner Losh }
9308e3e3a7aSWarner Losh 
9318e3e3a7aSWarner Losh 
9328e3e3a7aSWarner Losh static void simpleexp (LexState *ls, expdesc *v) {
9338e3e3a7aSWarner Losh   /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... |
9348e3e3a7aSWarner Losh                   constructor | FUNCTION body | suffixedexp */
9358e3e3a7aSWarner Losh   switch (ls->t.token) {
9368e3e3a7aSWarner Losh     case TK_FLT: {
9378e3e3a7aSWarner Losh       init_exp(v, VKFLT, 0);
9388e3e3a7aSWarner Losh       v->u.nval = ls->t.seminfo.r;
9398e3e3a7aSWarner Losh       break;
9408e3e3a7aSWarner Losh     }
9418e3e3a7aSWarner Losh     case TK_INT: {
9428e3e3a7aSWarner Losh       init_exp(v, VKINT, 0);
9438e3e3a7aSWarner Losh       v->u.ival = ls->t.seminfo.i;
9448e3e3a7aSWarner Losh       break;
9458e3e3a7aSWarner Losh     }
9468e3e3a7aSWarner Losh     case TK_STRING: {
9478e3e3a7aSWarner Losh       codestring(ls, v, ls->t.seminfo.ts);
9488e3e3a7aSWarner Losh       break;
9498e3e3a7aSWarner Losh     }
9508e3e3a7aSWarner Losh     case TK_NIL: {
9518e3e3a7aSWarner Losh       init_exp(v, VNIL, 0);
9528e3e3a7aSWarner Losh       break;
9538e3e3a7aSWarner Losh     }
9548e3e3a7aSWarner Losh     case TK_TRUE: {
9558e3e3a7aSWarner Losh       init_exp(v, VTRUE, 0);
9568e3e3a7aSWarner Losh       break;
9578e3e3a7aSWarner Losh     }
9588e3e3a7aSWarner Losh     case TK_FALSE: {
9598e3e3a7aSWarner Losh       init_exp(v, VFALSE, 0);
9608e3e3a7aSWarner Losh       break;
9618e3e3a7aSWarner Losh     }
9628e3e3a7aSWarner Losh     case TK_DOTS: {  /* vararg */
9638e3e3a7aSWarner Losh       FuncState *fs = ls->fs;
9648e3e3a7aSWarner Losh       check_condition(ls, fs->f->is_vararg,
9658e3e3a7aSWarner Losh                       "cannot use '...' outside a vararg function");
9668e3e3a7aSWarner Losh       init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
9678e3e3a7aSWarner Losh       break;
9688e3e3a7aSWarner Losh     }
9698e3e3a7aSWarner Losh     case '{': {  /* constructor */
9708e3e3a7aSWarner Losh       constructor(ls, v);
9718e3e3a7aSWarner Losh       return;
9728e3e3a7aSWarner Losh     }
9738e3e3a7aSWarner Losh     case TK_FUNCTION: {
9748e3e3a7aSWarner Losh       luaX_next(ls);
9758e3e3a7aSWarner Losh       body(ls, v, 0, ls->linenumber);
9768e3e3a7aSWarner Losh       return;
9778e3e3a7aSWarner Losh     }
9788e3e3a7aSWarner Losh     default: {
9798e3e3a7aSWarner Losh       suffixedexp(ls, v);
9808e3e3a7aSWarner Losh       return;
9818e3e3a7aSWarner Losh     }
9828e3e3a7aSWarner Losh   }
9838e3e3a7aSWarner Losh   luaX_next(ls);
9848e3e3a7aSWarner Losh }
9858e3e3a7aSWarner Losh 
9868e3e3a7aSWarner Losh 
9878e3e3a7aSWarner Losh static UnOpr getunopr (int op) {
9888e3e3a7aSWarner Losh   switch (op) {
9898e3e3a7aSWarner Losh     case TK_NOT: return OPR_NOT;
9908e3e3a7aSWarner Losh     case '-': return OPR_MINUS;
9918e3e3a7aSWarner Losh     case '~': return OPR_BNOT;
9928e3e3a7aSWarner Losh     case '#': return OPR_LEN;
9938e3e3a7aSWarner Losh     default: return OPR_NOUNOPR;
9948e3e3a7aSWarner Losh   }
9958e3e3a7aSWarner Losh }
9968e3e3a7aSWarner Losh 
9978e3e3a7aSWarner Losh 
9988e3e3a7aSWarner Losh static BinOpr getbinopr (int op) {
9998e3e3a7aSWarner Losh   switch (op) {
10008e3e3a7aSWarner Losh     case '+': return OPR_ADD;
10018e3e3a7aSWarner Losh     case '-': return OPR_SUB;
10028e3e3a7aSWarner Losh     case '*': return OPR_MUL;
10038e3e3a7aSWarner Losh     case '%': return OPR_MOD;
10048e3e3a7aSWarner Losh     case '^': return OPR_POW;
10058e3e3a7aSWarner Losh     case '/': return OPR_DIV;
10068e3e3a7aSWarner Losh     case TK_IDIV: return OPR_IDIV;
10078e3e3a7aSWarner Losh     case '&': return OPR_BAND;
10088e3e3a7aSWarner Losh     case '|': return OPR_BOR;
10098e3e3a7aSWarner Losh     case '~': return OPR_BXOR;
10108e3e3a7aSWarner Losh     case TK_SHL: return OPR_SHL;
10118e3e3a7aSWarner Losh     case TK_SHR: return OPR_SHR;
10128e3e3a7aSWarner Losh     case TK_CONCAT: return OPR_CONCAT;
10138e3e3a7aSWarner Losh     case TK_NE: return OPR_NE;
10148e3e3a7aSWarner Losh     case TK_EQ: return OPR_EQ;
10158e3e3a7aSWarner Losh     case '<': return OPR_LT;
10168e3e3a7aSWarner Losh     case TK_LE: return OPR_LE;
10178e3e3a7aSWarner Losh     case '>': return OPR_GT;
10188e3e3a7aSWarner Losh     case TK_GE: return OPR_GE;
10198e3e3a7aSWarner Losh     case TK_AND: return OPR_AND;
10208e3e3a7aSWarner Losh     case TK_OR: return OPR_OR;
10218e3e3a7aSWarner Losh     default: return OPR_NOBINOPR;
10228e3e3a7aSWarner Losh   }
10238e3e3a7aSWarner Losh }
10248e3e3a7aSWarner Losh 
10258e3e3a7aSWarner Losh 
10268e3e3a7aSWarner Losh static const struct {
10278e3e3a7aSWarner Losh   lu_byte left;  /* left priority for each binary operator */
10288e3e3a7aSWarner Losh   lu_byte right; /* right priority */
10298e3e3a7aSWarner Losh } priority[] = {  /* ORDER OPR */
10308e3e3a7aSWarner Losh    {10, 10}, {10, 10},           /* '+' '-' */
10318e3e3a7aSWarner Losh    {11, 11}, {11, 11},           /* '*' '%' */
10328e3e3a7aSWarner Losh    {14, 13},                  /* '^' (right associative) */
10338e3e3a7aSWarner Losh    {11, 11}, {11, 11},           /* '/' '//' */
10348e3e3a7aSWarner Losh    {6, 6}, {4, 4}, {5, 5},   /* '&' '|' '~' */
10358e3e3a7aSWarner Losh    {7, 7}, {7, 7},           /* '<<' '>>' */
10368e3e3a7aSWarner Losh    {9, 8},                   /* '..' (right associative) */
10378e3e3a7aSWarner Losh    {3, 3}, {3, 3}, {3, 3},   /* ==, <, <= */
10388e3e3a7aSWarner Losh    {3, 3}, {3, 3}, {3, 3},   /* ~=, >, >= */
10398e3e3a7aSWarner Losh    {2, 2}, {1, 1}            /* and, or */
10408e3e3a7aSWarner Losh };
10418e3e3a7aSWarner Losh 
10428e3e3a7aSWarner Losh #define UNARY_PRIORITY	12  /* priority for unary operators */
10438e3e3a7aSWarner Losh 
10448e3e3a7aSWarner Losh 
10458e3e3a7aSWarner Losh /*
10468e3e3a7aSWarner Losh ** subexpr -> (simpleexp | unop subexpr) { binop subexpr }
10478e3e3a7aSWarner Losh ** where 'binop' is any binary operator with a priority higher than 'limit'
10488e3e3a7aSWarner Losh */
10498e3e3a7aSWarner Losh static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
10508e3e3a7aSWarner Losh   BinOpr op;
10518e3e3a7aSWarner Losh   UnOpr uop;
10528e3e3a7aSWarner Losh   enterlevel(ls);
10538e3e3a7aSWarner Losh   uop = getunopr(ls->t.token);
10548e3e3a7aSWarner Losh   if (uop != OPR_NOUNOPR) {
10558e3e3a7aSWarner Losh     int line = ls->linenumber;
10568e3e3a7aSWarner Losh     luaX_next(ls);
10578e3e3a7aSWarner Losh     subexpr(ls, v, UNARY_PRIORITY);
10588e3e3a7aSWarner Losh     luaK_prefix(ls->fs, uop, v, line);
10598e3e3a7aSWarner Losh   }
10608e3e3a7aSWarner Losh   else simpleexp(ls, v);
10618e3e3a7aSWarner Losh   /* expand while operators have priorities higher than 'limit' */
10628e3e3a7aSWarner Losh   op = getbinopr(ls->t.token);
10638e3e3a7aSWarner Losh   while (op != OPR_NOBINOPR && priority[op].left > limit) {
10648e3e3a7aSWarner Losh     expdesc v2;
10658e3e3a7aSWarner Losh     BinOpr nextop;
10668e3e3a7aSWarner Losh     int line = ls->linenumber;
10678e3e3a7aSWarner Losh     luaX_next(ls);
10688e3e3a7aSWarner Losh     luaK_infix(ls->fs, op, v);
10698e3e3a7aSWarner Losh     /* read sub-expression with higher priority */
10708e3e3a7aSWarner Losh     nextop = subexpr(ls, &v2, priority[op].right);
10718e3e3a7aSWarner Losh     luaK_posfix(ls->fs, op, v, &v2, line);
10728e3e3a7aSWarner Losh     op = nextop;
10738e3e3a7aSWarner Losh   }
10748e3e3a7aSWarner Losh   leavelevel(ls);
10758e3e3a7aSWarner Losh   return op;  /* return first untreated operator */
10768e3e3a7aSWarner Losh }
10778e3e3a7aSWarner Losh 
10788e3e3a7aSWarner Losh 
10798e3e3a7aSWarner Losh static void expr (LexState *ls, expdesc *v) {
10808e3e3a7aSWarner Losh   subexpr(ls, v, 0);
10818e3e3a7aSWarner Losh }
10828e3e3a7aSWarner Losh 
10838e3e3a7aSWarner Losh /* }==================================================================== */
10848e3e3a7aSWarner Losh 
10858e3e3a7aSWarner Losh 
10868e3e3a7aSWarner Losh 
10878e3e3a7aSWarner Losh /*
10888e3e3a7aSWarner Losh ** {======================================================================
10898e3e3a7aSWarner Losh ** Rules for Statements
10908e3e3a7aSWarner Losh ** =======================================================================
10918e3e3a7aSWarner Losh */
10928e3e3a7aSWarner Losh 
10938e3e3a7aSWarner Losh 
10948e3e3a7aSWarner Losh static void block (LexState *ls) {
10958e3e3a7aSWarner Losh   /* block -> statlist */
10968e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
10978e3e3a7aSWarner Losh   BlockCnt bl;
10988e3e3a7aSWarner Losh   enterblock(fs, &bl, 0);
10998e3e3a7aSWarner Losh   statlist(ls);
11008e3e3a7aSWarner Losh   leaveblock(fs);
11018e3e3a7aSWarner Losh }
11028e3e3a7aSWarner Losh 
11038e3e3a7aSWarner Losh 
11048e3e3a7aSWarner Losh /*
11058e3e3a7aSWarner Losh ** structure to chain all variables in the left-hand side of an
11068e3e3a7aSWarner Losh ** assignment
11078e3e3a7aSWarner Losh */
11088e3e3a7aSWarner Losh struct LHS_assign {
11098e3e3a7aSWarner Losh   struct LHS_assign *prev;
11108e3e3a7aSWarner Losh   expdesc v;  /* variable (global, local, upvalue, or indexed) */
11118e3e3a7aSWarner Losh };
11128e3e3a7aSWarner Losh 
11138e3e3a7aSWarner Losh 
11148e3e3a7aSWarner Losh /*
11158e3e3a7aSWarner Losh ** check whether, in an assignment to an upvalue/local variable, the
11168e3e3a7aSWarner Losh ** upvalue/local variable is begin used in a previous assignment to a
11178e3e3a7aSWarner Losh ** table. If so, save original upvalue/local value in a safe place and
11188e3e3a7aSWarner Losh ** use this safe copy in the previous assignment.
11198e3e3a7aSWarner Losh */
11208e3e3a7aSWarner Losh static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
11218e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
11228e3e3a7aSWarner Losh   int extra = fs->freereg;  /* eventual position to save local variable */
11238e3e3a7aSWarner Losh   int conflict = 0;
11248e3e3a7aSWarner Losh   for (; lh; lh = lh->prev) {  /* check all previous assignments */
11258e3e3a7aSWarner Losh     if (lh->v.k == VINDEXED) {  /* assigning to a table? */
11268e3e3a7aSWarner Losh       /* table is the upvalue/local being assigned now? */
11278e3e3a7aSWarner Losh       if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {
11288e3e3a7aSWarner Losh         conflict = 1;
11298e3e3a7aSWarner Losh         lh->v.u.ind.vt = VLOCAL;
11308e3e3a7aSWarner Losh         lh->v.u.ind.t = extra;  /* previous assignment will use safe copy */
11318e3e3a7aSWarner Losh       }
11328e3e3a7aSWarner Losh       /* index is the local being assigned? (index cannot be upvalue) */
11338e3e3a7aSWarner Losh       if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {
11348e3e3a7aSWarner Losh         conflict = 1;
11358e3e3a7aSWarner Losh         lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
11368e3e3a7aSWarner Losh       }
11378e3e3a7aSWarner Losh     }
11388e3e3a7aSWarner Losh   }
11398e3e3a7aSWarner Losh   if (conflict) {
11408e3e3a7aSWarner Losh     /* copy upvalue/local value to a temporary (in position 'extra') */
11418e3e3a7aSWarner Losh     OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
11428e3e3a7aSWarner Losh     luaK_codeABC(fs, op, extra, v->u.info, 0);
11438e3e3a7aSWarner Losh     luaK_reserveregs(fs, 1);
11448e3e3a7aSWarner Losh   }
11458e3e3a7aSWarner Losh }
11468e3e3a7aSWarner Losh 
11478e3e3a7aSWarner Losh 
11488e3e3a7aSWarner Losh static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
11498e3e3a7aSWarner Losh   expdesc e;
11508e3e3a7aSWarner Losh   check_condition(ls, vkisvar(lh->v.k), "syntax error");
11518e3e3a7aSWarner Losh   if (testnext(ls, ',')) {  /* assignment -> ',' suffixedexp assignment */
11528e3e3a7aSWarner Losh     struct LHS_assign nv;
11538e3e3a7aSWarner Losh     nv.prev = lh;
11548e3e3a7aSWarner Losh     suffixedexp(ls, &nv.v);
11558e3e3a7aSWarner Losh     if (nv.v.k != VINDEXED)
11568e3e3a7aSWarner Losh       check_conflict(ls, lh, &nv.v);
11578e3e3a7aSWarner Losh     checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,
11588e3e3a7aSWarner Losh                     "C levels");
11598e3e3a7aSWarner Losh     assignment(ls, &nv, nvars+1);
11608e3e3a7aSWarner Losh   }
11618e3e3a7aSWarner Losh   else {  /* assignment -> '=' explist */
11628e3e3a7aSWarner Losh     int nexps;
11638e3e3a7aSWarner Losh     checknext(ls, '=');
11648e3e3a7aSWarner Losh     nexps = explist(ls, &e);
11658e3e3a7aSWarner Losh     if (nexps != nvars)
11668e3e3a7aSWarner Losh       adjust_assign(ls, nvars, nexps, &e);
11678e3e3a7aSWarner Losh     else {
11688e3e3a7aSWarner Losh       luaK_setoneret(ls->fs, &e);  /* close last expression */
11698e3e3a7aSWarner Losh       luaK_storevar(ls->fs, &lh->v, &e);
11708e3e3a7aSWarner Losh       return;  /* avoid default */
11718e3e3a7aSWarner Losh     }
11728e3e3a7aSWarner Losh   }
11738e3e3a7aSWarner Losh   init_exp(&e, VNONRELOC, ls->fs->freereg-1);  /* default assignment */
11748e3e3a7aSWarner Losh   luaK_storevar(ls->fs, &lh->v, &e);
11758e3e3a7aSWarner Losh }
11768e3e3a7aSWarner Losh 
11778e3e3a7aSWarner Losh 
11788e3e3a7aSWarner Losh static int cond (LexState *ls) {
11798e3e3a7aSWarner Losh   /* cond -> exp */
11808e3e3a7aSWarner Losh   expdesc v;
11818e3e3a7aSWarner Losh   expr(ls, &v);  /* read condition */
11828e3e3a7aSWarner Losh   if (v.k == VNIL) v.k = VFALSE;  /* 'falses' are all equal here */
11838e3e3a7aSWarner Losh   luaK_goiftrue(ls->fs, &v);
11848e3e3a7aSWarner Losh   return v.f;
11858e3e3a7aSWarner Losh }
11868e3e3a7aSWarner Losh 
11878e3e3a7aSWarner Losh 
11888e3e3a7aSWarner Losh static void gotostat (LexState *ls, int pc) {
11898e3e3a7aSWarner Losh   int line = ls->linenumber;
11908e3e3a7aSWarner Losh   TString *label;
11918e3e3a7aSWarner Losh   int g;
11928e3e3a7aSWarner Losh   if (testnext(ls, TK_GOTO))
11938e3e3a7aSWarner Losh     label = str_checkname(ls);
11948e3e3a7aSWarner Losh   else {
11958e3e3a7aSWarner Losh     luaX_next(ls);  /* skip break */
11968e3e3a7aSWarner Losh     label = luaS_new(ls->L, "break");
11978e3e3a7aSWarner Losh   }
11988e3e3a7aSWarner Losh   g = newlabelentry(ls, &ls->dyd->gt, label, line, pc);
11998e3e3a7aSWarner Losh   findlabel(ls, g);  /* close it if label already defined */
12008e3e3a7aSWarner Losh }
12018e3e3a7aSWarner Losh 
12028e3e3a7aSWarner Losh 
12038e3e3a7aSWarner Losh /* check for repeated labels on the same block */
12048e3e3a7aSWarner Losh static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
12058e3e3a7aSWarner Losh   int i;
12068e3e3a7aSWarner Losh   for (i = fs->bl->firstlabel; i < ll->n; i++) {
12078e3e3a7aSWarner Losh     if (eqstr(label, ll->arr[i].name)) {
12088e3e3a7aSWarner Losh       const char *msg = luaO_pushfstring(fs->ls->L,
12098e3e3a7aSWarner Losh                           "label '%s' already defined on line %d",
12108e3e3a7aSWarner Losh                           getstr(label), ll->arr[i].line);
12118e3e3a7aSWarner Losh       semerror(fs->ls, msg);
12128e3e3a7aSWarner Losh     }
12138e3e3a7aSWarner Losh   }
12148e3e3a7aSWarner Losh }
12158e3e3a7aSWarner Losh 
12168e3e3a7aSWarner Losh 
12178e3e3a7aSWarner Losh /* skip no-op statements */
12188e3e3a7aSWarner Losh static void skipnoopstat (LexState *ls) {
12198e3e3a7aSWarner Losh   while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
12208e3e3a7aSWarner Losh     statement(ls);
12218e3e3a7aSWarner Losh }
12228e3e3a7aSWarner Losh 
12238e3e3a7aSWarner Losh 
12248e3e3a7aSWarner Losh static void labelstat (LexState *ls, TString *label, int line) {
12258e3e3a7aSWarner Losh   /* label -> '::' NAME '::' */
12268e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
12278e3e3a7aSWarner Losh   Labellist *ll = &ls->dyd->label;
12288e3e3a7aSWarner Losh   int l;  /* index of new label being created */
12298e3e3a7aSWarner Losh   checkrepeated(fs, ll, label);  /* check for repeated labels */
12308e3e3a7aSWarner Losh   checknext(ls, TK_DBCOLON);  /* skip double colon */
12318e3e3a7aSWarner Losh   /* create new entry for this label */
12328e3e3a7aSWarner Losh   l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
12338e3e3a7aSWarner Losh   skipnoopstat(ls);  /* skip other no-op statements */
12348e3e3a7aSWarner Losh   if (block_follow(ls, 0)) {  /* label is last no-op statement in the block? */
12358e3e3a7aSWarner Losh     /* assume that locals are already out of scope */
12368e3e3a7aSWarner Losh     ll->arr[l].nactvar = fs->bl->nactvar;
12378e3e3a7aSWarner Losh   }
12388e3e3a7aSWarner Losh   findgotos(ls, &ll->arr[l]);
12398e3e3a7aSWarner Losh }
12408e3e3a7aSWarner Losh 
12418e3e3a7aSWarner Losh 
12428e3e3a7aSWarner Losh static void whilestat (LexState *ls, int line) {
12438e3e3a7aSWarner Losh   /* whilestat -> WHILE cond DO block END */
12448e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
12458e3e3a7aSWarner Losh   int whileinit;
12468e3e3a7aSWarner Losh   int condexit;
12478e3e3a7aSWarner Losh   BlockCnt bl;
12488e3e3a7aSWarner Losh   luaX_next(ls);  /* skip WHILE */
12498e3e3a7aSWarner Losh   whileinit = luaK_getlabel(fs);
12508e3e3a7aSWarner Losh   condexit = cond(ls);
12518e3e3a7aSWarner Losh   enterblock(fs, &bl, 1);
12528e3e3a7aSWarner Losh   checknext(ls, TK_DO);
12538e3e3a7aSWarner Losh   block(ls);
12548e3e3a7aSWarner Losh   luaK_jumpto(fs, whileinit);
12558e3e3a7aSWarner Losh   check_match(ls, TK_END, TK_WHILE, line);
12568e3e3a7aSWarner Losh   leaveblock(fs);
12578e3e3a7aSWarner Losh   luaK_patchtohere(fs, condexit);  /* false conditions finish the loop */
12588e3e3a7aSWarner Losh }
12598e3e3a7aSWarner Losh 
12608e3e3a7aSWarner Losh 
12618e3e3a7aSWarner Losh static void repeatstat (LexState *ls, int line) {
12628e3e3a7aSWarner Losh   /* repeatstat -> REPEAT block UNTIL cond */
12638e3e3a7aSWarner Losh   int condexit;
12648e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
12658e3e3a7aSWarner Losh   int repeat_init = luaK_getlabel(fs);
12668e3e3a7aSWarner Losh   BlockCnt bl1, bl2;
12678e3e3a7aSWarner Losh   enterblock(fs, &bl1, 1);  /* loop block */
12688e3e3a7aSWarner Losh   enterblock(fs, &bl2, 0);  /* scope block */
12698e3e3a7aSWarner Losh   luaX_next(ls);  /* skip REPEAT */
12708e3e3a7aSWarner Losh   statlist(ls);
12718e3e3a7aSWarner Losh   check_match(ls, TK_UNTIL, TK_REPEAT, line);
12728e3e3a7aSWarner Losh   condexit = cond(ls);  /* read condition (inside scope block) */
12738e3e3a7aSWarner Losh   if (bl2.upval)  /* upvalues? */
12748e3e3a7aSWarner Losh     luaK_patchclose(fs, condexit, bl2.nactvar);
12758e3e3a7aSWarner Losh   leaveblock(fs);  /* finish scope */
12768e3e3a7aSWarner Losh   luaK_patchlist(fs, condexit, repeat_init);  /* close the loop */
12778e3e3a7aSWarner Losh   leaveblock(fs);  /* finish loop */
12788e3e3a7aSWarner Losh }
12798e3e3a7aSWarner Losh 
12808e3e3a7aSWarner Losh 
12818e3e3a7aSWarner Losh static int exp1 (LexState *ls) {
12828e3e3a7aSWarner Losh   expdesc e;
12838e3e3a7aSWarner Losh   int reg;
12848e3e3a7aSWarner Losh   expr(ls, &e);
12858e3e3a7aSWarner Losh   luaK_exp2nextreg(ls->fs, &e);
12868e3e3a7aSWarner Losh   lua_assert(e.k == VNONRELOC);
12878e3e3a7aSWarner Losh   reg = e.u.info;
12888e3e3a7aSWarner Losh   return reg;
12898e3e3a7aSWarner Losh }
12908e3e3a7aSWarner Losh 
12918e3e3a7aSWarner Losh 
12928e3e3a7aSWarner Losh static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
12938e3e3a7aSWarner Losh   /* forbody -> DO block */
12948e3e3a7aSWarner Losh   BlockCnt bl;
12958e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
12968e3e3a7aSWarner Losh   int prep, endfor;
12978e3e3a7aSWarner Losh   adjustlocalvars(ls, 3);  /* control variables */
12988e3e3a7aSWarner Losh   checknext(ls, TK_DO);
12998e3e3a7aSWarner Losh   prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
13008e3e3a7aSWarner Losh   enterblock(fs, &bl, 0);  /* scope for declared variables */
13018e3e3a7aSWarner Losh   adjustlocalvars(ls, nvars);
13028e3e3a7aSWarner Losh   luaK_reserveregs(fs, nvars);
13038e3e3a7aSWarner Losh   block(ls);
13048e3e3a7aSWarner Losh   leaveblock(fs);  /* end of scope for declared variables */
13058e3e3a7aSWarner Losh   luaK_patchtohere(fs, prep);
13068e3e3a7aSWarner Losh   if (isnum)  /* numeric for? */
13078e3e3a7aSWarner Losh     endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP);
13088e3e3a7aSWarner Losh   else {  /* generic for */
13098e3e3a7aSWarner Losh     luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
13108e3e3a7aSWarner Losh     luaK_fixline(fs, line);
13118e3e3a7aSWarner Losh     endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);
13128e3e3a7aSWarner Losh   }
13138e3e3a7aSWarner Losh   luaK_patchlist(fs, endfor, prep + 1);
13148e3e3a7aSWarner Losh   luaK_fixline(fs, line);
13158e3e3a7aSWarner Losh }
13168e3e3a7aSWarner Losh 
13178e3e3a7aSWarner Losh 
13188e3e3a7aSWarner Losh static void fornum (LexState *ls, TString *varname, int line) {
13198e3e3a7aSWarner Losh   /* fornum -> NAME = exp1,exp1[,exp1] forbody */
13208e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
13218e3e3a7aSWarner Losh   int base = fs->freereg;
13228e3e3a7aSWarner Losh   new_localvarliteral(ls, "(for index)");
13238e3e3a7aSWarner Losh   new_localvarliteral(ls, "(for limit)");
13248e3e3a7aSWarner Losh   new_localvarliteral(ls, "(for step)");
13258e3e3a7aSWarner Losh   new_localvar(ls, varname);
13268e3e3a7aSWarner Losh   checknext(ls, '=');
13278e3e3a7aSWarner Losh   exp1(ls);  /* initial value */
13288e3e3a7aSWarner Losh   checknext(ls, ',');
13298e3e3a7aSWarner Losh   exp1(ls);  /* limit */
13308e3e3a7aSWarner Losh   if (testnext(ls, ','))
13318e3e3a7aSWarner Losh     exp1(ls);  /* optional step */
13328e3e3a7aSWarner Losh   else {  /* default step = 1 */
13338e3e3a7aSWarner Losh     luaK_codek(fs, fs->freereg, luaK_intK(fs, 1));
13348e3e3a7aSWarner Losh     luaK_reserveregs(fs, 1);
13358e3e3a7aSWarner Losh   }
13368e3e3a7aSWarner Losh   forbody(ls, base, line, 1, 1);
13378e3e3a7aSWarner Losh }
13388e3e3a7aSWarner Losh 
13398e3e3a7aSWarner Losh 
13408e3e3a7aSWarner Losh static void forlist (LexState *ls, TString *indexname) {
13418e3e3a7aSWarner Losh   /* forlist -> NAME {,NAME} IN explist forbody */
13428e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
13438e3e3a7aSWarner Losh   expdesc e;
13448e3e3a7aSWarner Losh   int nvars = 4;  /* gen, state, control, plus at least one declared var */
13458e3e3a7aSWarner Losh   int line;
13468e3e3a7aSWarner Losh   int base = fs->freereg;
13478e3e3a7aSWarner Losh   /* create control variables */
13488e3e3a7aSWarner Losh   new_localvarliteral(ls, "(for generator)");
13498e3e3a7aSWarner Losh   new_localvarliteral(ls, "(for state)");
13508e3e3a7aSWarner Losh   new_localvarliteral(ls, "(for control)");
13518e3e3a7aSWarner Losh   /* create declared variables */
13528e3e3a7aSWarner Losh   new_localvar(ls, indexname);
13538e3e3a7aSWarner Losh   while (testnext(ls, ',')) {
13548e3e3a7aSWarner Losh     new_localvar(ls, str_checkname(ls));
13558e3e3a7aSWarner Losh     nvars++;
13568e3e3a7aSWarner Losh   }
13578e3e3a7aSWarner Losh   checknext(ls, TK_IN);
13588e3e3a7aSWarner Losh   line = ls->linenumber;
13598e3e3a7aSWarner Losh   adjust_assign(ls, 3, explist(ls, &e), &e);
13608e3e3a7aSWarner Losh   luaK_checkstack(fs, 3);  /* extra space to call generator */
13618e3e3a7aSWarner Losh   forbody(ls, base, line, nvars - 3, 0);
13628e3e3a7aSWarner Losh }
13638e3e3a7aSWarner Losh 
13648e3e3a7aSWarner Losh 
13658e3e3a7aSWarner Losh static void forstat (LexState *ls, int line) {
13668e3e3a7aSWarner Losh   /* forstat -> FOR (fornum | forlist) END */
13678e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
13688e3e3a7aSWarner Losh   TString *varname;
13698e3e3a7aSWarner Losh   BlockCnt bl;
13708e3e3a7aSWarner Losh   enterblock(fs, &bl, 1);  /* scope for loop and control variables */
13718e3e3a7aSWarner Losh   luaX_next(ls);  /* skip 'for' */
13728e3e3a7aSWarner Losh   varname = str_checkname(ls);  /* first variable name */
13738e3e3a7aSWarner Losh   switch (ls->t.token) {
13748e3e3a7aSWarner Losh     case '=': fornum(ls, varname, line); break;
13758e3e3a7aSWarner Losh     case ',': case TK_IN: forlist(ls, varname); break;
13768e3e3a7aSWarner Losh     default: luaX_syntaxerror(ls, "'=' or 'in' expected");
13778e3e3a7aSWarner Losh   }
13788e3e3a7aSWarner Losh   check_match(ls, TK_END, TK_FOR, line);
13798e3e3a7aSWarner Losh   leaveblock(fs);  /* loop scope ('break' jumps to this point) */
13808e3e3a7aSWarner Losh }
13818e3e3a7aSWarner Losh 
13828e3e3a7aSWarner Losh 
13838e3e3a7aSWarner Losh static void test_then_block (LexState *ls, int *escapelist) {
13848e3e3a7aSWarner Losh   /* test_then_block -> [IF | ELSEIF] cond THEN block */
13858e3e3a7aSWarner Losh   BlockCnt bl;
13868e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
13878e3e3a7aSWarner Losh   expdesc v;
13888e3e3a7aSWarner Losh   int jf;  /* instruction to skip 'then' code (if condition is false) */
13898e3e3a7aSWarner Losh   luaX_next(ls);  /* skip IF or ELSEIF */
13908e3e3a7aSWarner Losh   expr(ls, &v);  /* read condition */
13918e3e3a7aSWarner Losh   checknext(ls, TK_THEN);
13928e3e3a7aSWarner Losh   if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) {
13938e3e3a7aSWarner Losh     luaK_goiffalse(ls->fs, &v);  /* will jump to label if condition is true */
13948e3e3a7aSWarner Losh     enterblock(fs, &bl, 0);  /* must enter block before 'goto' */
13958e3e3a7aSWarner Losh     gotostat(ls, v.t);  /* handle goto/break */
1396e112e9d2SKyle Evans     while (testnext(ls, ';')) {}  /* skip colons */
13978e3e3a7aSWarner Losh     if (block_follow(ls, 0)) {  /* 'goto' is the entire block? */
13988e3e3a7aSWarner Losh       leaveblock(fs);
13998e3e3a7aSWarner Losh       return;  /* and that is it */
14008e3e3a7aSWarner Losh     }
14018e3e3a7aSWarner Losh     else  /* must skip over 'then' part if condition is false */
14028e3e3a7aSWarner Losh       jf = luaK_jump(fs);
14038e3e3a7aSWarner Losh   }
14048e3e3a7aSWarner Losh   else {  /* regular case (not goto/break) */
14058e3e3a7aSWarner Losh     luaK_goiftrue(ls->fs, &v);  /* skip over block if condition is false */
14068e3e3a7aSWarner Losh     enterblock(fs, &bl, 0);
14078e3e3a7aSWarner Losh     jf = v.f;
14088e3e3a7aSWarner Losh   }
14098e3e3a7aSWarner Losh   statlist(ls);  /* 'then' part */
14108e3e3a7aSWarner Losh   leaveblock(fs);
14118e3e3a7aSWarner Losh   if (ls->t.token == TK_ELSE ||
14128e3e3a7aSWarner Losh       ls->t.token == TK_ELSEIF)  /* followed by 'else'/'elseif'? */
14138e3e3a7aSWarner Losh     luaK_concat(fs, escapelist, luaK_jump(fs));  /* must jump over it */
14148e3e3a7aSWarner Losh   luaK_patchtohere(fs, jf);
14158e3e3a7aSWarner Losh }
14168e3e3a7aSWarner Losh 
14178e3e3a7aSWarner Losh 
14188e3e3a7aSWarner Losh static void ifstat (LexState *ls, int line) {
14198e3e3a7aSWarner Losh   /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */
14208e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
14218e3e3a7aSWarner Losh   int escapelist = NO_JUMP;  /* exit list for finished parts */
14228e3e3a7aSWarner Losh   test_then_block(ls, &escapelist);  /* IF cond THEN block */
14238e3e3a7aSWarner Losh   while (ls->t.token == TK_ELSEIF)
14248e3e3a7aSWarner Losh     test_then_block(ls, &escapelist);  /* ELSEIF cond THEN block */
14258e3e3a7aSWarner Losh   if (testnext(ls, TK_ELSE))
14268e3e3a7aSWarner Losh     block(ls);  /* 'else' part */
14278e3e3a7aSWarner Losh   check_match(ls, TK_END, TK_IF, line);
14288e3e3a7aSWarner Losh   luaK_patchtohere(fs, escapelist);  /* patch escape list to 'if' end */
14298e3e3a7aSWarner Losh }
14308e3e3a7aSWarner Losh 
14318e3e3a7aSWarner Losh 
14328e3e3a7aSWarner Losh static void localfunc (LexState *ls) {
14338e3e3a7aSWarner Losh   expdesc b;
14348e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
14358e3e3a7aSWarner Losh   new_localvar(ls, str_checkname(ls));  /* new local variable */
14368e3e3a7aSWarner Losh   adjustlocalvars(ls, 1);  /* enter its scope */
14378e3e3a7aSWarner Losh   body(ls, &b, 0, ls->linenumber);  /* function created in next register */
14388e3e3a7aSWarner Losh   /* debug information will only see the variable after this point! */
14398e3e3a7aSWarner Losh   getlocvar(fs, b.u.info)->startpc = fs->pc;
14408e3e3a7aSWarner Losh }
14418e3e3a7aSWarner Losh 
14428e3e3a7aSWarner Losh 
14438e3e3a7aSWarner Losh static void localstat (LexState *ls) {
14448e3e3a7aSWarner Losh   /* stat -> LOCAL NAME {',' NAME} ['=' explist] */
14458e3e3a7aSWarner Losh   int nvars = 0;
14468e3e3a7aSWarner Losh   int nexps;
14478e3e3a7aSWarner Losh   expdesc e;
14488e3e3a7aSWarner Losh   do {
14498e3e3a7aSWarner Losh     new_localvar(ls, str_checkname(ls));
14508e3e3a7aSWarner Losh     nvars++;
14518e3e3a7aSWarner Losh   } while (testnext(ls, ','));
14528e3e3a7aSWarner Losh   if (testnext(ls, '='))
14538e3e3a7aSWarner Losh     nexps = explist(ls, &e);
14548e3e3a7aSWarner Losh   else {
14558e3e3a7aSWarner Losh     e.k = VVOID;
14568e3e3a7aSWarner Losh     nexps = 0;
14578e3e3a7aSWarner Losh   }
14588e3e3a7aSWarner Losh   adjust_assign(ls, nvars, nexps, &e);
14598e3e3a7aSWarner Losh   adjustlocalvars(ls, nvars);
14608e3e3a7aSWarner Losh }
14618e3e3a7aSWarner Losh 
14628e3e3a7aSWarner Losh 
14638e3e3a7aSWarner Losh static int funcname (LexState *ls, expdesc *v) {
14648e3e3a7aSWarner Losh   /* funcname -> NAME {fieldsel} [':' NAME] */
14658e3e3a7aSWarner Losh   int ismethod = 0;
14668e3e3a7aSWarner Losh   singlevar(ls, v);
14678e3e3a7aSWarner Losh   while (ls->t.token == '.')
14688e3e3a7aSWarner Losh     fieldsel(ls, v);
14698e3e3a7aSWarner Losh   if (ls->t.token == ':') {
14708e3e3a7aSWarner Losh     ismethod = 1;
14718e3e3a7aSWarner Losh     fieldsel(ls, v);
14728e3e3a7aSWarner Losh   }
14738e3e3a7aSWarner Losh   return ismethod;
14748e3e3a7aSWarner Losh }
14758e3e3a7aSWarner Losh 
14768e3e3a7aSWarner Losh 
14778e3e3a7aSWarner Losh static void funcstat (LexState *ls, int line) {
14788e3e3a7aSWarner Losh   /* funcstat -> FUNCTION funcname body */
14798e3e3a7aSWarner Losh   int ismethod;
14808e3e3a7aSWarner Losh   expdesc v, b;
14818e3e3a7aSWarner Losh   luaX_next(ls);  /* skip FUNCTION */
14828e3e3a7aSWarner Losh   ismethod = funcname(ls, &v);
14838e3e3a7aSWarner Losh   body(ls, &b, ismethod, line);
14848e3e3a7aSWarner Losh   luaK_storevar(ls->fs, &v, &b);
14858e3e3a7aSWarner Losh   luaK_fixline(ls->fs, line);  /* definition "happens" in the first line */
14868e3e3a7aSWarner Losh }
14878e3e3a7aSWarner Losh 
14888e3e3a7aSWarner Losh 
14898e3e3a7aSWarner Losh static void exprstat (LexState *ls) {
14908e3e3a7aSWarner Losh   /* stat -> func | assignment */
14918e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
14928e3e3a7aSWarner Losh   struct LHS_assign v;
14938e3e3a7aSWarner Losh   suffixedexp(ls, &v.v);
14948e3e3a7aSWarner Losh   if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */
14958e3e3a7aSWarner Losh     v.prev = NULL;
14968e3e3a7aSWarner Losh     assignment(ls, &v, 1);
14978e3e3a7aSWarner Losh   }
14988e3e3a7aSWarner Losh   else {  /* stat -> func */
14998e3e3a7aSWarner Losh     check_condition(ls, v.v.k == VCALL, "syntax error");
15008e3e3a7aSWarner Losh     SETARG_C(getinstruction(fs, &v.v), 1);  /* call statement uses no results */
15018e3e3a7aSWarner Losh   }
15028e3e3a7aSWarner Losh }
15038e3e3a7aSWarner Losh 
15048e3e3a7aSWarner Losh 
15058e3e3a7aSWarner Losh static void retstat (LexState *ls) {
15068e3e3a7aSWarner Losh   /* stat -> RETURN [explist] [';'] */
15078e3e3a7aSWarner Losh   FuncState *fs = ls->fs;
15088e3e3a7aSWarner Losh   expdesc e;
15098e3e3a7aSWarner Losh   int first, nret;  /* registers with returned values */
15108e3e3a7aSWarner Losh   if (block_follow(ls, 1) || ls->t.token == ';')
15118e3e3a7aSWarner Losh     first = nret = 0;  /* return no values */
15128e3e3a7aSWarner Losh   else {
15138e3e3a7aSWarner Losh     nret = explist(ls, &e);  /* optional return values */
15148e3e3a7aSWarner Losh     if (hasmultret(e.k)) {
15158e3e3a7aSWarner Losh       luaK_setmultret(fs, &e);
15168e3e3a7aSWarner Losh       if (e.k == VCALL && nret == 1) {  /* tail call? */
15178e3e3a7aSWarner Losh         SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
15188e3e3a7aSWarner Losh         lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
15198e3e3a7aSWarner Losh       }
15208e3e3a7aSWarner Losh       first = fs->nactvar;
15218e3e3a7aSWarner Losh       nret = LUA_MULTRET;  /* return all values */
15228e3e3a7aSWarner Losh     }
15238e3e3a7aSWarner Losh     else {
15248e3e3a7aSWarner Losh       if (nret == 1)  /* only one single value? */
15258e3e3a7aSWarner Losh         first = luaK_exp2anyreg(fs, &e);
15268e3e3a7aSWarner Losh       else {
15278e3e3a7aSWarner Losh         luaK_exp2nextreg(fs, &e);  /* values must go to the stack */
15288e3e3a7aSWarner Losh         first = fs->nactvar;  /* return all active values */
15298e3e3a7aSWarner Losh         lua_assert(nret == fs->freereg - first);
15308e3e3a7aSWarner Losh       }
15318e3e3a7aSWarner Losh     }
15328e3e3a7aSWarner Losh   }
15338e3e3a7aSWarner Losh   luaK_ret(fs, first, nret);
15348e3e3a7aSWarner Losh   testnext(ls, ';');  /* skip optional semicolon */
15358e3e3a7aSWarner Losh }
15368e3e3a7aSWarner Losh 
15378e3e3a7aSWarner Losh 
15388e3e3a7aSWarner Losh static void statement (LexState *ls) {
15398e3e3a7aSWarner Losh   int line = ls->linenumber;  /* may be needed for error messages */
15408e3e3a7aSWarner Losh   enterlevel(ls);
15418e3e3a7aSWarner Losh   switch (ls->t.token) {
15428e3e3a7aSWarner Losh     case ';': {  /* stat -> ';' (empty statement) */
15438e3e3a7aSWarner Losh       luaX_next(ls);  /* skip ';' */
15448e3e3a7aSWarner Losh       break;
15458e3e3a7aSWarner Losh     }
15468e3e3a7aSWarner Losh     case TK_IF: {  /* stat -> ifstat */
15478e3e3a7aSWarner Losh       ifstat(ls, line);
15488e3e3a7aSWarner Losh       break;
15498e3e3a7aSWarner Losh     }
15508e3e3a7aSWarner Losh     case TK_WHILE: {  /* stat -> whilestat */
15518e3e3a7aSWarner Losh       whilestat(ls, line);
15528e3e3a7aSWarner Losh       break;
15538e3e3a7aSWarner Losh     }
15548e3e3a7aSWarner Losh     case TK_DO: {  /* stat -> DO block END */
15558e3e3a7aSWarner Losh       luaX_next(ls);  /* skip DO */
15568e3e3a7aSWarner Losh       block(ls);
15578e3e3a7aSWarner Losh       check_match(ls, TK_END, TK_DO, line);
15588e3e3a7aSWarner Losh       break;
15598e3e3a7aSWarner Losh     }
15608e3e3a7aSWarner Losh     case TK_FOR: {  /* stat -> forstat */
15618e3e3a7aSWarner Losh       forstat(ls, line);
15628e3e3a7aSWarner Losh       break;
15638e3e3a7aSWarner Losh     }
15648e3e3a7aSWarner Losh     case TK_REPEAT: {  /* stat -> repeatstat */
15658e3e3a7aSWarner Losh       repeatstat(ls, line);
15668e3e3a7aSWarner Losh       break;
15678e3e3a7aSWarner Losh     }
15688e3e3a7aSWarner Losh     case TK_FUNCTION: {  /* stat -> funcstat */
15698e3e3a7aSWarner Losh       funcstat(ls, line);
15708e3e3a7aSWarner Losh       break;
15718e3e3a7aSWarner Losh     }
15728e3e3a7aSWarner Losh     case TK_LOCAL: {  /* stat -> localstat */
15738e3e3a7aSWarner Losh       luaX_next(ls);  /* skip LOCAL */
15748e3e3a7aSWarner Losh       if (testnext(ls, TK_FUNCTION))  /* local function? */
15758e3e3a7aSWarner Losh         localfunc(ls);
15768e3e3a7aSWarner Losh       else
15778e3e3a7aSWarner Losh         localstat(ls);
15788e3e3a7aSWarner Losh       break;
15798e3e3a7aSWarner Losh     }
15808e3e3a7aSWarner Losh     case TK_DBCOLON: {  /* stat -> label */
15818e3e3a7aSWarner Losh       luaX_next(ls);  /* skip double colon */
15828e3e3a7aSWarner Losh       labelstat(ls, str_checkname(ls), line);
15838e3e3a7aSWarner Losh       break;
15848e3e3a7aSWarner Losh     }
15858e3e3a7aSWarner Losh     case TK_RETURN: {  /* stat -> retstat */
15868e3e3a7aSWarner Losh       luaX_next(ls);  /* skip RETURN */
15878e3e3a7aSWarner Losh       retstat(ls);
15888e3e3a7aSWarner Losh       break;
15898e3e3a7aSWarner Losh     }
15908e3e3a7aSWarner Losh     case TK_BREAK:   /* stat -> breakstat */
15918e3e3a7aSWarner Losh     case TK_GOTO: {  /* stat -> 'goto' NAME */
15928e3e3a7aSWarner Losh       gotostat(ls, luaK_jump(ls->fs));
15938e3e3a7aSWarner Losh       break;
15948e3e3a7aSWarner Losh     }
15958e3e3a7aSWarner Losh     default: {  /* stat -> func | assignment */
15968e3e3a7aSWarner Losh       exprstat(ls);
15978e3e3a7aSWarner Losh       break;
15988e3e3a7aSWarner Losh     }
15998e3e3a7aSWarner Losh   }
16008e3e3a7aSWarner Losh   lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
16018e3e3a7aSWarner Losh              ls->fs->freereg >= ls->fs->nactvar);
16028e3e3a7aSWarner Losh   ls->fs->freereg = ls->fs->nactvar;  /* free registers */
16038e3e3a7aSWarner Losh   leavelevel(ls);
16048e3e3a7aSWarner Losh }
16058e3e3a7aSWarner Losh 
16068e3e3a7aSWarner Losh /* }====================================================================== */
16078e3e3a7aSWarner Losh 
16088e3e3a7aSWarner Losh 
16098e3e3a7aSWarner Losh /*
16108e3e3a7aSWarner Losh ** compiles the main function, which is a regular vararg function with an
16118e3e3a7aSWarner Losh ** upvalue named LUA_ENV
16128e3e3a7aSWarner Losh */
16138e3e3a7aSWarner Losh static void mainfunc (LexState *ls, FuncState *fs) {
16148e3e3a7aSWarner Losh   BlockCnt bl;
16158e3e3a7aSWarner Losh   expdesc v;
16168e3e3a7aSWarner Losh   open_func(ls, fs, &bl);
16178e3e3a7aSWarner Losh   fs->f->is_vararg = 1;  /* main function is always declared vararg */
16188e3e3a7aSWarner Losh   init_exp(&v, VLOCAL, 0);  /* create and... */
16198e3e3a7aSWarner Losh   newupvalue(fs, ls->envn, &v);  /* ...set environment upvalue */
1620*bf9580a1SKyle Evans   luaC_objbarrier(ls->L, fs->f, ls->envn);
16218e3e3a7aSWarner Losh   luaX_next(ls);  /* read first token */
16228e3e3a7aSWarner Losh   statlist(ls);  /* parse main body */
16238e3e3a7aSWarner Losh   check(ls, TK_EOS);
16248e3e3a7aSWarner Losh   close_func(ls);
16258e3e3a7aSWarner Losh }
16268e3e3a7aSWarner Losh 
16278e3e3a7aSWarner Losh 
16288e3e3a7aSWarner Losh LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
16298e3e3a7aSWarner Losh                        Dyndata *dyd, const char *name, int firstchar) {
16308e3e3a7aSWarner Losh   LexState lexstate;
16318e3e3a7aSWarner Losh   FuncState funcstate;
16328e3e3a7aSWarner Losh   LClosure *cl = luaF_newLclosure(L, 1);  /* create main closure */
16338e3e3a7aSWarner Losh   setclLvalue(L, L->top, cl);  /* anchor it (to avoid being collected) */
16348e3e3a7aSWarner Losh   luaD_inctop(L);
16358e3e3a7aSWarner Losh   lexstate.h = luaH_new(L);  /* create table for scanner */
16368e3e3a7aSWarner Losh   sethvalue(L, L->top, lexstate.h);  /* anchor it */
16378e3e3a7aSWarner Losh   luaD_inctop(L);
16388e3e3a7aSWarner Losh   funcstate.f = cl->p = luaF_newproto(L);
1639*bf9580a1SKyle Evans   luaC_objbarrier(L, cl, cl->p);
16408e3e3a7aSWarner Losh   funcstate.f->source = luaS_new(L, name);  /* create and anchor TString */
16418e3e3a7aSWarner Losh   lua_assert(iswhite(funcstate.f));  /* do not need barrier here */
16428e3e3a7aSWarner Losh   lexstate.buff = buff;
16438e3e3a7aSWarner Losh   lexstate.dyd = dyd;
16448e3e3a7aSWarner Losh   dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
16458e3e3a7aSWarner Losh   luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
16468e3e3a7aSWarner Losh   mainfunc(&lexstate, &funcstate);
16478e3e3a7aSWarner Losh   lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
16488e3e3a7aSWarner Losh   /* all scopes should be correctly finished */
16498e3e3a7aSWarner Losh   lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
16508e3e3a7aSWarner Losh   L->top--;  /* remove scanner's table */
16518e3e3a7aSWarner Losh   return cl;  /* closure is on the stack, too */
16528e3e3a7aSWarner Losh }
16538e3e3a7aSWarner Losh 
1654