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.
This commit is contained in:
Roberto Ierusalimschy
2019-07-03 14:18:07 -03:00
parent 8eca21c2e8
commit 4d46289331
3 changed files with 103 additions and 81 deletions

View File

@@ -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;