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