diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-03-14 15:01:52 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-03-14 15:01:52 -0300 |
| commit | 7ff21273d66541ac19ad817f90e8bcea5790f355 (patch) | |
| tree | 9798243bbc84da7f0ea3aa7316ba42b06b947e63 | |
| parent | 207dad86065acf4b6168bea1f13e88b7306a7440 (diff) | |
| download | lua-7ff21273d66541ac19ad817f90e8bcea5790f355.tar.gz lua-7ff21273d66541ac19ad817f90e8bcea5790f355.tar.bz2 lua-7ff21273d66541ac19ad817f90e8bcea5790f355.zip | |
implementation of `global' statement
| -rw-r--r-- | llimits.h | 8 | ||||
| -rw-r--r-- | lparser.c | 269 | ||||
| -rw-r--r-- | lparser.h | 36 | ||||
| -rw-r--r-- | ltests.c | 4 |
4 files changed, 211 insertions, 106 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: llimits.h,v 1.38 2002/03/05 16:22:54 roberto Exp roberto $ | 2 | ** $Id: llimits.h,v 1.39 2002/03/07 18:11:51 roberto Exp roberto $ |
| 3 | ** Limits, basic types, and some other `installation-dependent' definitions | 3 | ** Limits, basic types, and some other `installation-dependent' definitions |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -96,9 +96,9 @@ typedef unsigned long Instruction; | |||
| 96 | #define MAXSTACK 250 | 96 | #define MAXSTACK 250 |
| 97 | 97 | ||
| 98 | 98 | ||
| 99 | /* maximum number of local variables */ | 99 | /* maximum number of variables declared in a function */ |
| 100 | #ifndef MAXLOCALS | 100 | #ifndef MAXVARS |
| 101 | #define MAXLOCALS 200 /* arbitrary limit (<MAXSTACK) */ | 101 | #define MAXVARS 200 /* arbitrary limit (<MAXSTACK) */ |
| 102 | #endif | 102 | #endif |
| 103 | 103 | ||
| 104 | 104 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lparser.c,v 1.167 2002/02/14 21:46:58 roberto Exp $ | 2 | ** $Id: lparser.c,v 1.168 2002/03/08 19:10:32 roberto Exp roberto $ |
| 3 | ** Lua Parser | 3 | ** Lua Parser |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -24,14 +24,17 @@ | |||
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | /* | 26 | /* |
| 27 | ** nodes for break list (list of active breakable loops) | 27 | ** nodes for block list (list of active blocks) |
| 28 | */ | 28 | */ |
| 29 | typedef struct Breaklabel { | 29 | typedef struct BlockCnt { |
| 30 | struct Breaklabel *previous; /* chain */ | 30 | struct BlockCnt *previous; /* chain */ |
| 31 | int breaklist; /* list of jumps out of this loop */ | 31 | int breaklist; /* list of jumps out of this loop */ |
| 32 | int nactloc; /* # of active local variables outside the breakable structure */ | 32 | int nactloc; /* # active local variables outside the breakable structure */ |
| 33 | } Breaklabel; | 33 | int nactvar; |
| 34 | 34 | int defaultglob; | |
| 35 | int upval; /* true if some variable in the block is an upvalue */ | ||
| 36 | int isbreakable; /* true if `block' is a loop */ | ||
| 37 | } BlockCnt; | ||
| 35 | 38 | ||
| 36 | 39 | ||
| 37 | 40 | ||
| @@ -77,9 +80,7 @@ static void check (LexState *ls, int c) { | |||
| 77 | } | 80 | } |
| 78 | 81 | ||
| 79 | 82 | ||
| 80 | static void check_condition (LexState *ls, int c, const char *msg) { | 83 | #define check_condition(ls,c,msg) { if (!(c)) luaK_error(ls, msg); } |
| 81 | if (!c) luaK_error(ls, msg); | ||
| 82 | } | ||
| 83 | 84 | ||
| 84 | 85 | ||
| 85 | static int optional (LexState *ls, int c) { | 86 | static int optional (LexState *ls, int c) { |
| @@ -143,41 +144,51 @@ static int luaI_registerlocalvar (LexState *ls, TString *varname) { | |||
| 143 | } | 144 | } |
| 144 | 145 | ||
| 145 | 146 | ||
| 146 | static void new_localvar (LexState *ls, TString *name, int n) { | 147 | static vardesc *new_var (LexState *ls, int n) { |
| 147 | FuncState *fs = ls->fs; | 148 | FuncState *fs = ls->fs; |
| 148 | luaX_checklimit(ls, fs->nactloc+n+1, MAXLOCALS, "local variables"); | 149 | luaX_checklimit(ls, fs->nactvar+n+1, MAXVARS, "variables"); |
| 149 | fs->actloc[fs->nactloc+n] = luaI_registerlocalvar(ls, name); | 150 | return &fs->actvar[fs->nactvar+n]; |
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | static void new_localvar (LexState *ls, TString *name, int n) { | ||
| 155 | vardesc *v = new_var(ls, n); | ||
| 156 | v->k = VLOCAL; | ||
| 157 | v->i = luaI_registerlocalvar(ls, name); | ||
| 158 | v->level = ls->fs->nactloc + n; | ||
| 150 | } | 159 | } |
| 151 | 160 | ||
| 152 | 161 | ||
| 153 | static void adjustlocalvars (LexState *ls, int nvars) { | 162 | static void adjustlocalvars (LexState *ls, int nvars) { |
| 154 | FuncState *fs = ls->fs; | 163 | FuncState *fs = ls->fs; |
| 155 | while (nvars--) { | 164 | while (nvars--) { |
| 156 | fs->f->locvars[fs->actloc[fs->nactloc]].startpc = fs->pc; | 165 | lua_assert(fs->actvar[fs->nactvar].k == VLOCAL); |
| 157 | resetbit(fs->wasup, fs->nactloc); | 166 | fs->f->locvars[fs->actvar[fs->nactvar].i].startpc = fs->pc; |
| 167 | fs->nactvar++; | ||
| 158 | fs->nactloc++; | 168 | fs->nactloc++; |
| 159 | } | 169 | } |
| 160 | } | 170 | } |
| 161 | 171 | ||
| 162 | 172 | ||
| 163 | static void closelevel (LexState *ls, int level) { | 173 | static void adjustglobalvars (LexState *ls, int nvars, int level) { |
| 164 | FuncState *fs = ls->fs; | 174 | FuncState *fs = ls->fs; |
| 165 | int i; | 175 | while (nvars--) { |
| 166 | for (i=level; i<fs->nactloc; i++) | 176 | fs->actvar[fs->nactvar].k = VGLOBAL; |
| 167 | if (testbit(fs->wasup, i)) { | 177 | fs->actvar[fs->nactvar].level = level; |
| 168 | luaK_codeABC(fs, OP_CLOSE, level, 0, 0); | 178 | fs->nactvar++; |
| 169 | return; | 179 | } |
| 170 | } | ||
| 171 | return; /* nothing to close */ | ||
| 172 | } | 180 | } |
| 173 | 181 | ||
| 174 | 182 | ||
| 175 | static void removelocalvars (LexState *ls, int nvars, int toclose) { | 183 | static void removevars (LexState *ls, int tolevel) { |
| 176 | FuncState *fs = ls->fs; | 184 | FuncState *fs = ls->fs; |
| 177 | if (toclose) | 185 | while (fs->nactvar > tolevel) { |
| 178 | closelevel(ls, fs->nactloc - nvars); | 186 | fs->nactvar--; |
| 179 | while (nvars--) | 187 | if (fs->actvar[fs->nactvar].k == VLOCAL) { |
| 180 | fs->f->locvars[fs->actloc[--fs->nactloc]].endpc = fs->pc; | 188 | fs->nactloc--; |
| 189 | fs->f->locvars[fs->actvar[fs->nactvar].i].endpc = fs->pc; | ||
| 190 | } | ||
| 191 | } | ||
| 181 | } | 192 | } |
| 182 | 193 | ||
| 183 | 194 | ||
| @@ -186,6 +197,12 @@ static void new_localvarstr (LexState *ls, const char *name, int n) { | |||
| 186 | } | 197 | } |
| 187 | 198 | ||
| 188 | 199 | ||
| 200 | static void create_local (LexState *ls, const char *name) { | ||
| 201 | new_localvarstr(ls, name, 0); | ||
| 202 | adjustlocalvars(ls, 1); | ||
| 203 | } | ||
| 204 | |||
| 205 | |||
| 189 | static int indexupvalue (FuncState *fs, expdesc *v) { | 206 | static int indexupvalue (FuncState *fs, expdesc *v) { |
| 190 | int i; | 207 | int i; |
| 191 | for (i=0; i<fs->f->nupvalues; i++) { | 208 | for (i=0; i<fs->f->nupvalues; i++) { |
| @@ -199,28 +216,72 @@ static int indexupvalue (FuncState *fs, expdesc *v) { | |||
| 199 | } | 216 | } |
| 200 | 217 | ||
| 201 | 218 | ||
| 202 | static void singlevar (FuncState *fs, TString *n, expdesc *var, int baselevel) { | 219 | static vardesc *searchvar (FuncState *fs, TString *n) { |
| 203 | if (fs == NULL) | 220 | int i; |
| 204 | init_exp(var, VGLOBAL, 0); /* not local in any level; global variable */ | 221 | for (i=fs->nactvar-1; i >= 0; i--) { |
| 205 | else { /* look up at current level */ | 222 | vardesc *v = &fs->actvar[i]; |
| 206 | int i; | 223 | if (v->k == VLOCAL ? n == fs->f->locvars[v->i].varname |
| 207 | for (i=fs->nactloc-1; i >= 0; i--) { | 224 | : n == tsvalue(&fs->f->k[v->i])) |
| 208 | if (n == fs->f->locvars[fs->actloc[i]].varname) { | 225 | return v; |
| 209 | if (!baselevel) | 226 | } |
| 210 | setbit(fs->wasup, i); /* will be upvalue in some other level */ | 227 | return NULL; /* not found */ |
| 211 | init_exp(var, VLOCAL, i); | 228 | } |
| 212 | return; | 229 | |
| 230 | |||
| 231 | static void markupval (FuncState *fs, int level) { | ||
| 232 | BlockCnt *bl = fs->bl; | ||
| 233 | while (bl && bl->nactloc > level) bl = bl->previous; | ||
| 234 | if (bl) bl->upval = 1; | ||
| 235 | } | ||
| 236 | |||
| 237 | |||
| 238 | static int singlevar_aux (FuncState *fs, TString *n, expdesc *var, int nd) { | ||
| 239 | if (fs == NULL) { /* no more levels? */ | ||
| 240 | init_exp(var, VGLOBAL, NO_REG); /* default is free global */ | ||
| 241 | return VNIL; /* not found */ | ||
| 242 | } | ||
| 243 | else { | ||
| 244 | vardesc *v = searchvar(fs, n); /* look up at current level */ | ||
| 245 | if (v) { | ||
| 246 | if (v->level == NO_REG) { /* free global? */ | ||
| 247 | lua_assert(v->k == VGLOBAL); | ||
| 248 | init_exp(var, VGLOBAL, NO_REG); | ||
| 213 | } | 249 | } |
| 250 | else | ||
| 251 | init_exp(var, VLOCAL, v->level); | ||
| 252 | return v->k; | ||
| 214 | } | 253 | } |
| 215 | /* not found at current level; try upper one */ | 254 | else { /* not found at current level; try upper one */ |
| 216 | singlevar(fs->prev, n, var, 0); | 255 | int k = singlevar_aux(fs->prev, n, var, nd && fs->defaultglob == NO_REG); |
| 217 | if (var->k == VGLOBAL) { | 256 | if (var->k == VGLOBAL) { |
| 218 | if (baselevel) | 257 | if (k == VNIL && nd && fs->defaultglob != NO_REG) { |
| 219 | var->info = luaK_stringK(fs, n); /* info points to global name */ | 258 | init_exp(var, VLOCAL, fs->defaultglob); |
| 259 | k = VGLOBAL; /* now there is a declaration */ | ||
| 260 | } | ||
| 261 | } | ||
| 262 | else { /* LOCAL or UPVAL */ | ||
| 263 | if (var->k == VLOCAL) | ||
| 264 | markupval(fs->prev, var->info); /* local will be used as an upval */ | ||
| 265 | var->info = indexupvalue(fs, var); | ||
| 266 | var->k = VUPVAL; /* upvalue in this level */ | ||
| 267 | } | ||
| 268 | return k; | ||
| 220 | } | 269 | } |
| 221 | else { /* local variable in some upper level? */ | 270 | } |
| 222 | var->info = indexupvalue(fs, var); | 271 | } |
| 223 | var->k = VUPVAL; /* upvalue in this level */ | 272 | |
| 273 | |||
| 274 | static void singlevar (FuncState *fs, TString *n, expdesc *var) { | ||
| 275 | int k = singlevar_aux(fs, n, var, 1); | ||
| 276 | if (k == VNIL || k == VGLOBAL) { /* global? */ | ||
| 277 | if (var->k == VGLOBAL) /* free global? */ | ||
| 278 | var->info = luaK_stringK(fs, n); | ||
| 279 | else { /* `indexed' global */ | ||
| 280 | expdesc e; | ||
| 281 | codestring(fs->ls, &e, n); | ||
| 282 | luaK_exp2anyreg(fs, var); | ||
| 283 | var->aux = luaK_exp2RK(fs, &e); | ||
| 284 | var->k = VINDEXED; | ||
| 224 | } | 285 | } |
| 225 | } | 286 | } |
| 226 | } | 287 | } |
| @@ -250,29 +311,38 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { | |||
| 250 | static void code_params (LexState *ls, int nparams, int dots) { | 311 | static void code_params (LexState *ls, int nparams, int dots) { |
| 251 | FuncState *fs = ls->fs; | 312 | FuncState *fs = ls->fs; |
| 252 | adjustlocalvars(ls, nparams); | 313 | adjustlocalvars(ls, nparams); |
| 253 | luaX_checklimit(ls, fs->nactloc, MAXPARAMS, "parameters"); | 314 | luaX_checklimit(ls, fs->nactvar, MAXPARAMS, "parameters"); |
| 254 | fs->f->numparams = cast(lu_byte, fs->nactloc); | 315 | fs->f->numparams = cast(lu_byte, fs->nactloc); |
| 255 | fs->f->is_vararg = cast(lu_byte, dots); | 316 | fs->f->is_vararg = cast(lu_byte, dots); |
| 256 | if (dots) { | 317 | if (dots) |
| 257 | new_localvarstr(ls, "arg", 0); | 318 | create_local(ls, "arg"); |
| 258 | adjustlocalvars(ls, 1); | ||
| 259 | } | ||
| 260 | luaK_reserveregs(fs, fs->nactloc); /* reserve register for parameters */ | 319 | luaK_reserveregs(fs, fs->nactloc); /* reserve register for parameters */ |
| 261 | } | 320 | } |
| 262 | 321 | ||
| 263 | 322 | ||
| 264 | static void enterbreak (FuncState *fs, Breaklabel *bl) { | 323 | static void enterblock (FuncState *fs, BlockCnt *bl, int isbreakable) { |
| 265 | bl->breaklist = NO_JUMP; | 324 | bl->breaklist = NO_JUMP; |
| 325 | bl->isbreakable = isbreakable; | ||
| 266 | bl->nactloc = fs->nactloc; | 326 | bl->nactloc = fs->nactloc; |
| 327 | bl->nactvar = fs->nactvar; | ||
| 328 | bl->defaultglob = fs->defaultglob; | ||
| 329 | bl->upval = 0; | ||
| 267 | bl->previous = fs->bl; | 330 | bl->previous = fs->bl; |
| 268 | fs->bl = bl; | 331 | fs->bl = bl; |
| 269 | } | 332 | } |
| 270 | 333 | ||
| 271 | 334 | ||
| 272 | static void leavebreak (FuncState *fs, Breaklabel *bl) { | 335 | static void leaveblock (FuncState *fs) { |
| 336 | BlockCnt *bl = fs->bl; | ||
| 273 | fs->bl = bl->previous; | 337 | fs->bl = bl->previous; |
| 274 | luaK_patchtohere(fs, bl->breaklist); | 338 | removevars(fs->ls, bl->nactvar); |
| 339 | if (bl->upval) | ||
| 340 | luaK_codeABC(fs, OP_CLOSE, bl->nactloc, 0, 0); | ||
| 275 | lua_assert(bl->nactloc == fs->nactloc); | 341 | lua_assert(bl->nactloc == fs->nactloc); |
| 342 | lua_assert(bl->nactvar == fs->nactvar); | ||
| 343 | fs->defaultglob = bl->defaultglob; | ||
| 344 | fs->freereg = bl->nactloc; /* free registers used by locals */ | ||
| 345 | luaK_patchtohere(fs, bl->breaklist); | ||
| 276 | } | 346 | } |
| 277 | 347 | ||
| 278 | 348 | ||
| @@ -308,7 +378,9 @@ static void open_func (LexState *ls, FuncState *fs) { | |||
| 308 | fs->nlineinfo = 0; | 378 | fs->nlineinfo = 0; |
| 309 | fs->nlocvars = 0; | 379 | fs->nlocvars = 0; |
| 310 | fs->nactloc = 0; | 380 | fs->nactloc = 0; |
| 381 | fs->nactvar = 0; | ||
| 311 | fs->lastline = 0; | 382 | fs->lastline = 0; |
| 383 | fs->defaultglob = NO_REG; /* default is free globals */ | ||
| 312 | fs->bl = NULL; | 384 | fs->bl = NULL; |
| 313 | f->code = NULL; | 385 | f->code = NULL; |
| 314 | f->source = ls->source; | 386 | f->source = ls->source; |
| @@ -322,7 +394,7 @@ static void close_func (LexState *ls) { | |||
| 322 | lua_State *L = ls->L; | 394 | lua_State *L = ls->L; |
| 323 | FuncState *fs = ls->fs; | 395 | FuncState *fs = ls->fs; |
| 324 | Proto *f = fs->f; | 396 | Proto *f = fs->f; |
| 325 | removelocalvars(ls, fs->nactloc, 0); | 397 | removevars(ls, 0); |
| 326 | luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ | 398 | luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ |
| 327 | luaK_getlabel(fs); /* close eventual list of pending jumps */ | 399 | luaK_getlabel(fs); /* close eventual list of pending jumps */ |
| 328 | lua_assert(G(L)->roottable == fs->h); | 400 | lua_assert(G(L)->roottable == fs->h); |
| @@ -352,8 +424,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z) { | |||
| 352 | open_func(&lexstate, &funcstate); | 424 | open_func(&lexstate, &funcstate); |
| 353 | next(&lexstate); /* read first token */ | 425 | next(&lexstate); /* read first token */ |
| 354 | chunk(&lexstate); | 426 | chunk(&lexstate); |
| 355 | check_condition(&lexstate, (lexstate.t.token == TK_EOS), | 427 | check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected"); |
| 356 | "<eof> expected"); | ||
| 357 | close_func(&lexstate); | 428 | close_func(&lexstate); |
| 358 | lua_assert(funcstate.prev == NULL); | 429 | lua_assert(funcstate.prev == NULL); |
| 359 | lua_assert(funcstate.f->nupvalues == 0); | 430 | lua_assert(funcstate.f->nupvalues == 0); |
| @@ -593,13 +664,13 @@ static void prefixexp (LexState *ls, expdesc *v) { | |||
| 593 | return; | 664 | return; |
| 594 | } | 665 | } |
| 595 | case TK_NAME: { | 666 | case TK_NAME: { |
| 596 | singlevar(ls->fs, str_checkname(ls), v, 1); | 667 | singlevar(ls->fs, str_checkname(ls), v); |
| 597 | next(ls); | 668 | next(ls); |
| 598 | return; | 669 | return; |
| 599 | } | 670 | } |
| 600 | case '%': { /* for compatibility only */ | 671 | case '%': { /* for compatibility only */ |
| 601 | next(ls); /* skip `%' */ | 672 | next(ls); /* skip `%' */ |
| 602 | singlevar(ls->fs, str_checkname(ls), v, 1); | 673 | singlevar(ls->fs, str_checkname(ls), v); |
| 603 | check_condition(ls, v->k == VUPVAL, "global upvalues are obsolete"); | 674 | check_condition(ls, v->k == VUPVAL, "global upvalues are obsolete"); |
| 604 | next(ls); | 675 | next(ls); |
| 605 | return; | 676 | return; |
| @@ -797,10 +868,11 @@ static int block_follow (int token) { | |||
| 797 | static void block (LexState *ls) { | 868 | static void block (LexState *ls) { |
| 798 | /* block -> chunk */ | 869 | /* block -> chunk */ |
| 799 | FuncState *fs = ls->fs; | 870 | FuncState *fs = ls->fs; |
| 800 | int nactloc = fs->nactloc; | 871 | BlockCnt bl; |
| 872 | enterblock(fs, &bl, 0); | ||
| 801 | chunk(ls); | 873 | chunk(ls); |
| 802 | removelocalvars(ls, fs->nactloc - nactloc, 1); | 874 | lua_assert(bl.breaklist == NO_JUMP); |
| 803 | fs->freereg = nactloc; /* free registers used by locals */ | 875 | leaveblock(fs); |
| 804 | } | 876 | } |
| 805 | 877 | ||
| 806 | 878 | ||
| @@ -887,8 +959,8 @@ static void whilestat (LexState *ls, int line) { | |||
| 887 | FuncState *fs = ls->fs; | 959 | FuncState *fs = ls->fs; |
| 888 | int while_init = luaK_getlabel(fs); | 960 | int while_init = luaK_getlabel(fs); |
| 889 | expdesc v; | 961 | expdesc v; |
| 890 | Breaklabel bl; | 962 | BlockCnt bl; |
| 891 | enterbreak(fs, &bl); | 963 | enterblock(fs, &bl, 1); |
| 892 | next(ls); | 964 | next(ls); |
| 893 | cond(ls, &v); | 965 | cond(ls, &v); |
| 894 | check(ls, TK_DO); | 966 | check(ls, TK_DO); |
| @@ -896,7 +968,7 @@ static void whilestat (LexState *ls, int line) { | |||
| 896 | luaK_patchlist(fs, luaK_jump(fs), while_init); | 968 | luaK_patchlist(fs, luaK_jump(fs), while_init); |
| 897 | luaK_patchtohere(fs, v.f); | 969 | luaK_patchtohere(fs, v.f); |
| 898 | check_match(ls, TK_END, TK_WHILE, line); | 970 | check_match(ls, TK_END, TK_WHILE, line); |
| 899 | leavebreak(fs, &bl); | 971 | leaveblock(fs); |
| 900 | } | 972 | } |
| 901 | 973 | ||
| 902 | 974 | ||
| @@ -905,14 +977,14 @@ static void repeatstat (LexState *ls, int line) { | |||
| 905 | FuncState *fs = ls->fs; | 977 | FuncState *fs = ls->fs; |
| 906 | int repeat_init = luaK_getlabel(fs); | 978 | int repeat_init = luaK_getlabel(fs); |
| 907 | expdesc v; | 979 | expdesc v; |
| 908 | Breaklabel bl; | 980 | BlockCnt bl; |
| 909 | enterbreak(fs, &bl); | 981 | enterblock(fs, &bl, 1); |
| 910 | next(ls); | 982 | next(ls); |
| 911 | block(ls); | 983 | block(ls); |
| 912 | check_match(ls, TK_UNTIL, TK_REPEAT, line); | 984 | check_match(ls, TK_UNTIL, TK_REPEAT, line); |
| 913 | cond(ls, &v); | 985 | cond(ls, &v); |
| 914 | luaK_patchlist(fs, v.f, repeat_init); | 986 | luaK_patchlist(fs, v.f, repeat_init); |
| 915 | leavebreak(fs, &bl); | 987 | leaveblock(fs); |
| 916 | } | 988 | } |
| 917 | 989 | ||
| 918 | 990 | ||
| @@ -949,7 +1021,6 @@ static void fornum (LexState *ls, TString *varname) { | |||
| 949 | block(ls); | 1021 | block(ls); |
| 950 | luaK_patchtohere(fs, prep-1); | 1022 | luaK_patchtohere(fs, prep-1); |
| 951 | luaK_patchlist(fs, luaK_codeAsBc(fs, OP_FORLOOP, base, NO_JUMP), prep); | 1023 | luaK_patchlist(fs, luaK_codeAsBc(fs, OP_FORLOOP, base, NO_JUMP), prep); |
| 952 | removelocalvars(ls, 3, 1); | ||
| 953 | } | 1024 | } |
| 954 | 1025 | ||
| 955 | 1026 | ||
| @@ -977,7 +1048,6 @@ static void forlist (LexState *ls, TString *indexname) { | |||
| 977 | block(ls); | 1048 | block(ls); |
| 978 | luaK_patchlist(fs, luaK_jump(fs), prep-1); | 1049 | luaK_patchlist(fs, luaK_jump(fs), prep-1); |
| 979 | luaK_patchtohere(fs, prep); | 1050 | luaK_patchtohere(fs, prep); |
| 980 | removelocalvars(ls, nvars+1, 1); | ||
| 981 | } | 1051 | } |
| 982 | 1052 | ||
| 983 | 1053 | ||
| @@ -985,8 +1055,8 @@ static void forstat (LexState *ls, int line) { | |||
| 985 | /* forstat -> fornum | forlist */ | 1055 | /* forstat -> fornum | forlist */ |
| 986 | FuncState *fs = ls->fs; | 1056 | FuncState *fs = ls->fs; |
| 987 | TString *varname; | 1057 | TString *varname; |
| 988 | Breaklabel bl; | 1058 | BlockCnt bl; |
| 989 | enterbreak(fs, &bl); | 1059 | enterblock(fs, &bl, 1); |
| 990 | next(ls); /* skip `for' */ | 1060 | next(ls); /* skip `for' */ |
| 991 | varname = str_checkname(ls); /* first variable name */ | 1061 | varname = str_checkname(ls); /* first variable name */ |
| 992 | next(ls); /* skip var name */ | 1062 | next(ls); /* skip var name */ |
| @@ -996,7 +1066,7 @@ static void forstat (LexState *ls, int line) { | |||
| 996 | default: luaK_error(ls, "`=' or `in' expected"); | 1066 | default: luaK_error(ls, "`=' or `in' expected"); |
| 997 | } | 1067 | } |
| 998 | check_match(ls, TK_END, TK_FOR, line); | 1068 | check_match(ls, TK_END, TK_FOR, line); |
| 999 | leavebreak(fs, &bl); | 1069 | leaveblock(fs); |
| 1000 | } | 1070 | } |
| 1001 | 1071 | ||
| 1002 | 1072 | ||
| @@ -1054,10 +1124,37 @@ static void localstat (LexState *ls) { | |||
| 1054 | } | 1124 | } |
| 1055 | 1125 | ||
| 1056 | 1126 | ||
| 1127 | static void globalstat (LexState *ls) { | ||
| 1128 | /* stat -> GLOBAL NAME {`,' NAME} [IN exp] | GLOBAL IN exp */ | ||
| 1129 | FuncState *fs = ls->fs; | ||
| 1130 | next(ls); /* skip GLOBAL */ | ||
| 1131 | if (optional(ls, TK_IN)) { /* default declaration? */ | ||
| 1132 | exp1(ls); | ||
| 1133 | fs->defaultglob = fs->freereg - 1; | ||
| 1134 | create_local(ls, "(global table)"); | ||
| 1135 | } | ||
| 1136 | else { | ||
| 1137 | int nvars = 0; | ||
| 1138 | do { | ||
| 1139 | vardesc *v = new_var(ls, nvars++); | ||
| 1140 | v->i = luaK_stringK(ls->fs, str_checkname(ls)); | ||
| 1141 | next(ls); /* skip name */ | ||
| 1142 | } while (optional(ls, ',')); | ||
| 1143 | if (!optional(ls, TK_IN)) | ||
| 1144 | adjustglobalvars(ls, nvars, NO_REG); /* free globals */ | ||
| 1145 | else { | ||
| 1146 | exp1(ls); | ||
| 1147 | adjustglobalvars(ls, nvars, ls->fs->freereg - 1); | ||
| 1148 | create_local(ls, "(global table)"); | ||
| 1149 | } | ||
| 1150 | } | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | |||
| 1057 | static int funcname (LexState *ls, expdesc *v) { | 1154 | static int funcname (LexState *ls, expdesc *v) { |
| 1058 | /* funcname -> NAME {field} [`:' NAME] */ | 1155 | /* funcname -> NAME {field} [`:' NAME] */ |
| 1059 | int needself = 0; | 1156 | int needself = 0; |
| 1060 | singlevar(ls->fs, str_checkname(ls), v, 1); | 1157 | singlevar(ls->fs, str_checkname(ls), v); |
| 1061 | next(ls); /* skip var name */ | 1158 | next(ls); /* skip var name */ |
| 1062 | while (ls->t.token == '.') { | 1159 | while (ls->t.token == '.') { |
| 1063 | luaY_field(ls, v); | 1160 | luaY_field(ls, v); |
| @@ -1125,11 +1222,17 @@ static void retstat (LexState *ls) { | |||
| 1125 | static void breakstat (LexState *ls) { | 1222 | static void breakstat (LexState *ls) { |
| 1126 | /* stat -> BREAK [NAME] */ | 1223 | /* stat -> BREAK [NAME] */ |
| 1127 | FuncState *fs = ls->fs; | 1224 | FuncState *fs = ls->fs; |
| 1128 | Breaklabel *bl = fs->bl; | 1225 | BlockCnt *bl = fs->bl; |
| 1226 | int upval = 0; | ||
| 1227 | next(ls); /* skip BREAK */ | ||
| 1228 | while (bl && !bl->isbreakable) { | ||
| 1229 | upval |= bl->upval; | ||
| 1230 | bl = bl->previous; | ||
| 1231 | } | ||
| 1129 | if (!bl) | 1232 | if (!bl) |
| 1130 | luaK_error(ls, "no loop to break"); | 1233 | luaK_error(ls, "no loop to break"); |
| 1131 | next(ls); /* skip BREAK */ | 1234 | if (upval) |
| 1132 | closelevel(ls, bl->nactloc); | 1235 | luaK_codeABC(fs, OP_CLOSE, bl->nactloc, 0, 0); |
| 1133 | luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); | 1236 | luaK_concat(fs, &bl->breaklist, luaK_jump(fs)); |
| 1134 | } | 1237 | } |
| 1135 | 1238 | ||
| @@ -1167,6 +1270,10 @@ static int statement (LexState *ls) { | |||
| 1167 | localstat(ls); | 1270 | localstat(ls); |
| 1168 | return 0; | 1271 | return 0; |
| 1169 | } | 1272 | } |
| 1273 | case TK_GLOBAL: { /* stat -> globalstat */ | ||
| 1274 | globalstat(ls); | ||
| 1275 | return 0; | ||
| 1276 | } | ||
| 1170 | case TK_RETURN: { /* stat -> retstat */ | 1277 | case TK_RETURN: { /* stat -> retstat */ |
| 1171 | retstat(ls); | 1278 | retstat(ls); |
| 1172 | return 1; /* must be last statement */ | 1279 | return 1; /* must be last statement */ |
| @@ -1207,10 +1314,8 @@ static void body (LexState *ls, expdesc *e, int needself, int line) { | |||
| 1207 | open_func(ls, &new_fs); | 1314 | open_func(ls, &new_fs); |
| 1208 | new_fs.f->lineDefined = line; | 1315 | new_fs.f->lineDefined = line; |
| 1209 | check(ls, '('); | 1316 | check(ls, '('); |
| 1210 | if (needself) { | 1317 | if (needself) |
| 1211 | new_localvarstr(ls, "self", 0); | 1318 | create_local(ls, "self"); |
| 1212 | adjustlocalvars(ls, 1); | ||
| 1213 | } | ||
| 1214 | parlist(ls); | 1319 | parlist(ls); |
| 1215 | check(ls, ')'); | 1320 | check(ls, ')'); |
| 1216 | chunk(ls); | 1321 | chunk(ls); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lparser.h,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ | 2 | ** $Id: lparser.h,v 1.39 2002/02/08 22:42:41 roberto Exp roberto $ |
| 3 | ** Lua Parser | 3 | ** Lua Parser |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -13,18 +13,6 @@ | |||
| 13 | #include "lzio.h" | 13 | #include "lzio.h" |
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | |||
| 17 | /* small implementation of bit arrays */ | ||
| 18 | |||
| 19 | #define BPW (CHAR_BIT*sizeof(unsigned int)) /* bits per word */ | ||
| 20 | |||
| 21 | #define words2bits(b) (((b)-1)/BPW + 1) | ||
| 22 | |||
| 23 | #define setbit(a, b) ((a)[(b)/BPW] |= (1 << (b)%BPW)) | ||
| 24 | #define resetbit(a, b) ((a)[(b)/BPW] &= ~((1 << (b)%BPW))) | ||
| 25 | #define testbit(a, b) ((a)[(b)/BPW] & (1 << (b)%BPW)) | ||
| 26 | |||
| 27 | |||
| 28 | /* | 16 | /* |
| 29 | ** Expression descriptor | 17 | ** Expression descriptor |
| 30 | */ | 18 | */ |
| @@ -37,7 +25,7 @@ typedef enum { | |||
| 37 | VK, /* info = index of constant in `k' */ | 25 | VK, /* info = index of constant in `k' */ |
| 38 | VLOCAL, /* info = local register */ | 26 | VLOCAL, /* info = local register */ |
| 39 | VUPVAL, /* info = index of upvalue in `upvalues' */ | 27 | VUPVAL, /* info = index of upvalue in `upvalues' */ |
| 40 | VGLOBAL, /* info = index of global name in `k' */ | 28 | VGLOBAL, /* info = index of table; aux = index of global name in `k' */ |
| 41 | VINDEXED, /* info = table register; aux = index register (or `k') */ | 29 | VINDEXED, /* info = table register; aux = index register (or `k') */ |
| 42 | VRELOCABLE, /* info = instruction pc */ | 30 | VRELOCABLE, /* info = instruction pc */ |
| 43 | VNONRELOC, /* info = result register */ | 31 | VNONRELOC, /* info = result register */ |
| @@ -53,6 +41,18 @@ typedef struct expdesc { | |||
| 53 | } expdesc; | 41 | } expdesc; |
| 54 | 42 | ||
| 55 | 43 | ||
| 44 | /* describe declared variables */ | ||
| 45 | typedef struct vardesc { | ||
| 46 | int i; /* if local, its index in `locvars'; | ||
| 47 | if global, its name index in `k' */ | ||
| 48 | lu_byte k; | ||
| 49 | lu_byte level; /* if local, stack level; | ||
| 50 | if global, corresponding local (NO_REG for free globals) */ | ||
| 51 | } vardesc; | ||
| 52 | |||
| 53 | |||
| 54 | struct BlockCnt; /* defined in lparser.c */ | ||
| 55 | |||
| 56 | /* state needed to generate code for a given function */ | 56 | /* state needed to generate code for a given function */ |
| 57 | typedef struct FuncState { | 57 | typedef struct FuncState { |
| 58 | Proto *f; /* current function header */ | 58 | Proto *f; /* current function header */ |
| @@ -60,21 +60,21 @@ typedef struct FuncState { | |||
| 60 | struct FuncState *prev; /* enclosing function */ | 60 | struct FuncState *prev; /* enclosing function */ |
| 61 | struct LexState *ls; /* lexical state */ | 61 | struct LexState *ls; /* lexical state */ |
| 62 | struct lua_State *L; /* copy of the Lua state */ | 62 | struct lua_State *L; /* copy of the Lua state */ |
| 63 | struct Breaklabel *bl; /* chain of breakable blocks */ | 63 | struct BlockCnt *bl; /* chain of current blocks */ |
| 64 | int pc; /* next position to code (equivalent to `ncode') */ | 64 | int pc; /* next position to code (equivalent to `ncode') */ |
| 65 | int lasttarget; /* `pc' of last `jump target' */ | 65 | int lasttarget; /* `pc' of last `jump target' */ |
| 66 | int jlt; /* list of jumps to `lasttarget' */ | 66 | int jlt; /* list of jumps to `lasttarget' */ |
| 67 | int freereg; /* first free register */ | 67 | int freereg; /* first free register */ |
| 68 | int defaultglob; /* where to look for non-declared globals */ | ||
| 68 | int nk; /* number of elements in `k' */ | 69 | int nk; /* number of elements in `k' */ |
| 69 | int np; /* number of elements in `p' */ | 70 | int np; /* number of elements in `p' */ |
| 70 | int nlineinfo; /* number of elements in `lineinfo' */ | 71 | int nlineinfo; /* number of elements in `lineinfo' */ |
| 71 | int nlocvars; /* number of elements in `locvars' */ | 72 | int nlocvars; /* number of elements in `locvars' */ |
| 72 | int nactloc; /* number of active local variables */ | 73 | int nactloc; /* number of active local variables */ |
| 74 | int nactvar; /* number of elements in array `actvar' */ | ||
| 73 | int lastline; /* line where last `lineinfo' was generated */ | 75 | int lastline; /* line where last `lineinfo' was generated */ |
| 74 | expdesc upvalues[MAXUPVALUES]; /* upvalues */ | 76 | expdesc upvalues[MAXUPVALUES]; /* upvalues */ |
| 75 | int actloc[MAXLOCALS]; /* local-variable stack (indices to locvars) */ | 77 | vardesc actvar[MAXVARS]; /* declared-variable stack */ |
| 76 | unsigned int wasup[words2bits(MAXLOCALS)]; /* bit array to mark whether a | ||
| 77 | local variable was used as upvalue at some level */ | ||
| 78 | } FuncState; | 78 | } FuncState; |
| 79 | 79 | ||
| 80 | 80 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 1.110 2002/03/04 15:26:56 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 1.111 2002/03/04 21:29:41 roberto Exp roberto $ |
| 3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -219,7 +219,7 @@ static int get_limits (lua_State *L) { | |||
| 219 | lua_newtable(L); | 219 | lua_newtable(L); |
| 220 | setnameval(L, "BITS_INT", BITS_INT); | 220 | setnameval(L, "BITS_INT", BITS_INT); |
| 221 | setnameval(L, "LFPF", LFIELDS_PER_FLUSH); | 221 | setnameval(L, "LFPF", LFIELDS_PER_FLUSH); |
| 222 | setnameval(L, "MAXLOCALS", MAXLOCALS); | 222 | setnameval(L, "MAXVARS", MAXVARS); |
| 223 | setnameval(L, "MAXPARAMS", MAXPARAMS); | 223 | setnameval(L, "MAXPARAMS", MAXPARAMS); |
| 224 | setnameval(L, "MAXSTACK", MAXSTACK); | 224 | setnameval(L, "MAXSTACK", MAXSTACK); |
| 225 | setnameval(L, "MAXUPVALUES", MAXUPVALUES); | 225 | setnameval(L, "MAXUPVALUES", MAXUPVALUES); |
