From 4d46289331395a845c5de1f6c0e0fe873c50db4f Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy <roberto@inf.puc-rio.br> Date: Wed, 3 Jul 2019 14:18:07 -0300 Subject: Local attributes can be used in list of local variables The syntax for local attributes ('const'/'toclose') was unified with the regular syntax for local variables, so that we can have variables with attributes in local definitions with multiple names; for instance: local <toclose> f, <const> err = io.open(fname) This new syntax does not implement constant propagation, yet. This commit also has some small improvements to the manual. --- lparser.c | 90 +++++++++++++++++++++++++++++---------------------------------- 1 file changed, 41 insertions(+), 49 deletions(-) (limited to 'lparser.c') diff --git a/lparser.c b/lparser.c index 875f7d04..52486e08 100644 --- a/lparser.c +++ b/lparser.c @@ -1656,13 +1656,50 @@ static void localfunc (LexState *ls) { } -static void commonlocalstat (LexState *ls) { - /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ +static int getlocalattribute (LexState *ls) { + /* ATTRIB -> ['<' Name '>'] */ + if (testnext(ls, '<')) { + const char *attr = getstr(str_checkname(ls)); + checknext(ls, '>'); + if (strcmp(attr, "const") == 0) + return 1; /* read-only variable */ + else if (strcmp(attr, "toclose") == 0) + return 2; /* to-be-closed variable */ + else + luaK_semerror(ls, + luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); + } + return 0; +} + + +static void checktoclose (LexState *ls, int toclose) { + if (toclose != -1) { /* is there a to-be-closed variable? */ + FuncState *fs = ls->fs; + markupval(fs, fs->nactvar + toclose + 1); + fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ + luaK_codeABC(fs, OP_TBC, fs->nactvar + toclose, 0, 0); + } +} + + +static void localstat (LexState *ls) { + /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */ + int toclose = -1; /* index of to-be-closed variable (if any) */ int nvars = 0; int nexps; expdesc e; do { - new_localvar(ls, str_checkname(ls)); + int kind = getlocalattribute(ls); + Vardesc *var = new_localvar(ls, str_checkname(ls)); + if (kind != 0) { /* is there an attribute? */ + var->ro = 1; /* all attributes make variable read-only */ + if (kind == 2) { /* to-be-closed? */ + if (toclose != -1) /* one already present? */ + luaK_semerror(ls, "multiple to-be-closed variables in local list"); + toclose = nvars; + } + } nvars++; } while (testnext(ls, ',')); if (testnext(ls, '=')) @@ -1672,56 +1709,11 @@ static void commonlocalstat (LexState *ls) { nexps = 0; } adjust_assign(ls, nvars, nexps, &e); + checktoclose(ls, toclose); adjustlocalvars(ls, nvars); } -static void tocloselocalstat (LexState *ls, Vardesc *var) { - FuncState *fs = ls->fs; - var->ro = 1; /* to-be-closed variables are always read-only */ - markupval(fs, fs->nactvar + 1); - fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ - luaK_codeABC(fs, OP_TBC, fs->nactvar, 0, 0); -} - - -static void checkattrib (LexState *ls, TString *attr, Vardesc *var) { - if (strcmp(getstr(attr), "const") == 0) - var->ro = 1; /* set variable as read-only */ - else if (strcmp(getstr(attr), "toclose") == 0) - tocloselocalstat(ls, var); - else - luaK_semerror(ls, - luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); -} - - -static void attriblocalstat (LexState *ls) { - FuncState *fs = ls->fs; - Vardesc *var; - expdesc e; - TString *attr = str_checkname(ls); - testnext(ls, '>'); - var = new_localvar(ls, str_checkname(ls)); - checknext(ls, '='); - expr(ls, &e); - checkattrib(ls, attr, var); - luaK_tonumeral(fs, &e, &var->val); - luaK_exp2nextreg(fs, &e); - adjustlocalvars(ls, 1); -} - - -static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {',' NAME} ['=' explist] - | LOCAL *toclose NAME '=' exp */ - if (testnext(ls, '<')) - attriblocalstat(ls); - else - commonlocalstat(ls); -} - - static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {fieldsel} [':' NAME] */ int ismethod = 0; -- cgit v1.2.3-55-g6feb