diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-20 17:36:05 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-20 17:36:05 -0300 |
| commit | be05c444818989463dc307eed283503d391f93eb (patch) | |
| tree | 16e08bf2e0256a1aeffcd848379af98577aec602 | |
| parent | 6d53701c7a0dc4736d824fd891ee6f22265d0d68 (diff) | |
| download | lua-be05c444818989463dc307eed283503d391f93eb.tar.gz lua-be05c444818989463dc307eed283503d391f93eb.tar.bz2 lua-be05c444818989463dc307eed283503d391f93eb.zip | |
New way to control preambular declaration
Validity of the preambular global declaration in controled together
with all declarations, when checking variable names.
| -rw-r--r-- | lparser.c | 33 | ||||
| -rw-r--r-- | lparser.h | 3 | ||||
| -rw-r--r-- | testes/db.lua | 6 | ||||
| -rw-r--r-- | testes/goto.lua | 18 |
4 files changed, 45 insertions, 15 deletions
| @@ -54,7 +54,6 @@ typedef struct BlockCnt { | |||
| 54 | lu_byte upval; /* true if some variable in the block is an upvalue */ | 54 | lu_byte upval; /* true if some variable in the block is an upvalue */ |
| 55 | lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */ | 55 | lu_byte isloop; /* 1 if 'block' is a loop; 2 if it has pending breaks */ |
| 56 | lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ | 56 | lu_byte insidetbc; /* true if inside the scope of a to-be-closed var. */ |
| 57 | lu_byte globdec; /* true if inside the scope of any global declaration */ | ||
| 58 | } BlockCnt; | 57 | } BlockCnt; |
| 59 | 58 | ||
| 60 | 59 | ||
| @@ -399,22 +398,35 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { | |||
| 399 | /* | 398 | /* |
| 400 | ** Look for an active variable with the name 'n' in the | 399 | ** Look for an active variable with the name 'n' in the |
| 401 | ** function 'fs'. If found, initialize 'var' with it and return | 400 | ** function 'fs'. If found, initialize 'var' with it and return |
| 402 | ** its expression kind; otherwise return -1. | 401 | ** its expression kind; otherwise return -1. While searching, |
| 402 | ** var->u.info==-1 means that the preambular global declaration is | ||
| 403 | ** active (the default while there is no other global declaration); | ||
| 404 | ** var->u.info==-2 means there is no active collective declaration | ||
| 405 | ** (some previous global declaration but no collective declaration); | ||
| 406 | ** and var->u.info>=0 points to the inner-most (the first one found) | ||
| 407 | ** collective declaration, if there is one. | ||
| 403 | */ | 408 | */ |
| 404 | static int searchvar (FuncState *fs, TString *n, expdesc *var) { | 409 | static int searchvar (FuncState *fs, TString *n, expdesc *var) { |
| 405 | int i; | 410 | int i; |
| 406 | for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { | 411 | for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { |
| 407 | Vardesc *vd = getlocalvardesc(fs, i); | 412 | Vardesc *vd = getlocalvardesc(fs, i); |
| 408 | if (vd->vd.name == NULL) { /* 'global *'? */ | 413 | if (varglobal(vd)) { /* global declaration? */ |
| 409 | if (var->u.info == -1) { /* no previous collective declaration? */ | 414 | if (vd->vd.name == NULL) { /* collective declaration? */ |
| 410 | var->u.info = fs->firstlocal + i; /* will use this one as default */ | 415 | if (var->u.info < 0) /* no previous collective declaration? */ |
| 416 | var->u.info = fs->firstlocal + i; /* this is the first one */ | ||
| 417 | } | ||
| 418 | else { /* global name */ | ||
| 419 | if (eqstr(n, vd->vd.name)) { /* found? */ | ||
| 420 | init_exp(var, VGLOBAL, fs->firstlocal + i); | ||
| 421 | return VGLOBAL; | ||
| 422 | } | ||
| 423 | else if (var->u.info == -1) /* active preambular declaration? */ | ||
| 424 | var->u.info = -2; /* invalidate preambular declaration */ | ||
| 411 | } | 425 | } |
| 412 | } | 426 | } |
| 413 | else if (eqstr(n, vd->vd.name)) { /* found? */ | 427 | else if (eqstr(n, vd->vd.name)) { /* found? */ |
| 414 | if (vd->vd.kind == RDKCTC) /* compile-time constant? */ | 428 | if (vd->vd.kind == RDKCTC) /* compile-time constant? */ |
| 415 | init_exp(var, VCONST, fs->firstlocal + i); | 429 | init_exp(var, VCONST, fs->firstlocal + i); |
| 416 | else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST) | ||
| 417 | init_exp(var, VGLOBAL, fs->firstlocal + i); | ||
| 418 | else /* local variable */ | 430 | else /* local variable */ |
| 419 | init_var(fs, var, i); | 431 | init_var(fs, var, i); |
| 420 | return cast_int(var->k); | 432 | return cast_int(var->k); |
| @@ -486,7 +498,7 @@ static void buildvar (LexState *ls, TString *varname, expdesc *var) { | |||
| 486 | expdesc key; | 498 | expdesc key; |
| 487 | int info = var->u.info; | 499 | int info = var->u.info; |
| 488 | /* global by default in the scope of a global declaration? */ | 500 | /* global by default in the scope of a global declaration? */ |
| 489 | if (info == -1 && fs->bl->globdec) | 501 | if (info == -2) |
| 490 | luaK_semerror(ls, "variable '%s' not declared", getstr(varname)); | 502 | luaK_semerror(ls, "variable '%s' not declared", getstr(varname)); |
| 491 | singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ | 503 | singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ |
| 492 | if (var->k == VGLOBAL) | 504 | if (var->k == VGLOBAL) |
| @@ -692,10 +704,6 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { | |||
| 692 | bl->upval = 0; | 704 | bl->upval = 0; |
| 693 | /* inherit 'insidetbc' from enclosing block */ | 705 | /* inherit 'insidetbc' from enclosing block */ |
| 694 | bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc); | 706 | bl->insidetbc = (fs->bl != NULL && fs->bl->insidetbc); |
| 695 | /* inherit 'globdec' from enclosing block or enclosing function */ | ||
| 696 | bl->globdec = fs->bl != NULL ? fs->bl->globdec | ||
| 697 | : fs->prev != NULL ? fs->prev->bl->globdec | ||
| 698 | : 0; /* chunk's first block */ | ||
| 699 | bl->previous = fs->bl; /* link block in function's block list */ | 707 | bl->previous = fs->bl; /* link block in function's block list */ |
| 700 | fs->bl = bl; | 708 | fs->bl = bl; |
| 701 | lua_assert(fs->freereg == luaY_nvarstack(fs)); | 709 | lua_assert(fs->freereg == luaY_nvarstack(fs)); |
| @@ -1855,7 +1863,6 @@ static void globalfunc (LexState *ls, int line) { | |||
| 1855 | static void globalstatfunc (LexState *ls, int line) { | 1863 | static void globalstatfunc (LexState *ls, int line) { |
| 1856 | /* stat -> GLOBAL globalfunc | GLOBAL globalstat */ | 1864 | /* stat -> GLOBAL globalfunc | GLOBAL globalstat */ |
| 1857 | luaX_next(ls); /* skip 'global' */ | 1865 | luaX_next(ls); /* skip 'global' */ |
| 1858 | ls->fs->bl->globdec = 1; /* in the scope of a global declaration */ | ||
| 1859 | if (testnext(ls, TK_FUNCTION)) | 1866 | if (testnext(ls, TK_FUNCTION)) |
| 1860 | globalfunc(ls, line); | 1867 | globalfunc(ls, line); |
| 1861 | else | 1868 | else |
| @@ -105,6 +105,9 @@ typedef struct expdesc { | |||
| 105 | /* variables that live in registers */ | 105 | /* variables that live in registers */ |
| 106 | #define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) | 106 | #define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) |
| 107 | 107 | ||
| 108 | /* test for global variables */ | ||
| 109 | #define varglobal(v) ((v)->vd.kind >= GDKREG) | ||
| 110 | |||
| 108 | 111 | ||
| 109 | /* description of an active variable */ | 112 | /* description of an active variable */ |
| 110 | typedef union Vardesc { | 113 | typedef union Vardesc { |
diff --git a/testes/db.lua b/testes/db.lua index ae204c41..0f174f17 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
| @@ -349,9 +349,11 @@ end, "crl") | |||
| 349 | 349 | ||
| 350 | 350 | ||
| 351 | function f(a,b) | 351 | function f(a,b) |
| 352 | global collectgarbage, assert, g, string | 352 | -- declare some globals to check that they don't interfere with 'getlocal' |
| 353 | global collectgarbage | ||
| 353 | collectgarbage() | 354 | collectgarbage() |
| 354 | local _, x = debug.getlocal(1, 1) | 355 | local _, x = debug.getlocal(1, 1) |
| 356 | global assert, g, string | ||
| 355 | local _, y = debug.getlocal(1, 2) | 357 | local _, y = debug.getlocal(1, 2) |
| 356 | assert(x == a and y == b) | 358 | assert(x == a and y == b) |
| 357 | assert(debug.setlocal(2, 3, "pera") == "AA".."AA") | 359 | assert(debug.setlocal(2, 3, "pera") == "AA".."AA") |
| @@ -387,7 +389,9 @@ function g (...) | |||
| 387 | f(AAAA,B) | 389 | f(AAAA,B) |
| 388 | assert(AAAA == "pera" and B == "manga") | 390 | assert(AAAA == "pera" and B == "manga") |
| 389 | do | 391 | do |
| 392 | global * | ||
| 390 | local B = 13 | 393 | local B = 13 |
| 394 | global<const> assert | ||
| 391 | local x,y = debug.getlocal(1,5) | 395 | local x,y = debug.getlocal(1,5) |
| 392 | assert(x == 'B' and y == 13) | 396 | assert(x == 'B' and y == 13) |
| 393 | end | 397 | end |
diff --git a/testes/goto.lua b/testes/goto.lua index d7730061..7e40fc4f 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
| @@ -364,7 +364,23 @@ do | |||
| 364 | print(X) -- Ok to use | 364 | print(X) -- Ok to use |
| 365 | Y = 1 -- ERROR | 365 | Y = 1 -- ERROR |
| 366 | ]], "assign to const variable 'Y'") | 366 | ]], "assign to const variable 'Y'") |
| 367 | 367 | ||
| 368 | checkerr([[ | ||
| 369 | global *; | ||
| 370 | Y = X -- Ok to use | ||
| 371 | global<const> *; | ||
| 372 | Y = 1 -- ERROR | ||
| 373 | ]], "assign to const variable 'Y'") | ||
| 374 | |||
| 375 | global * | ||
| 376 | Y = 10 | ||
| 377 | assert(_ENV.Y == 10) | ||
| 378 | global<const> * | ||
| 379 | local x = Y | ||
| 380 | global * | ||
| 381 | Y = x + Y | ||
| 382 | assert(_ENV.Y == 20) | ||
| 383 | |||
| 368 | end | 384 | end |
| 369 | 385 | ||
| 370 | print'OK' | 386 | print'OK' |
