lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,

in a previous mail I talked about allowing assignments to upvalues.
Attached is a patch that does this.  It goes even further:
the '%' character to introduce upvalues is removed as is the limit-
ation to only access locals of the first upper level.

Don't take me wrong.  I know that these changes will never make it
into the standard Lua.  I just wrote it to see how it effects the
parser, how it modifies the semantics, and to make clear what I
meant with writeable upvalues.

The changes aren't that much.  I even think, that a lot of special
craft for upvalues is removed.  The major change is a rewriting
of the singlevar function to return an additional kind of vari-
able (VUPVALUE).  A new opcode (SETUPVALUE) is introduced to
change upvalues.  What remains is removing the handling of the
'%' char.

A nice effect of the new singlevar function is that locals that
are accessed by lower functions are automatically propagated
downwards across intermediate functions.  This allows access
to arbitrary locals within the lexical scope.

I don't want to withhold one downside of these changes: globals
may no longer be upvalues.  It's syntactically impossible to
write it.  If you want this, you have to copy the global to
a local first.

Another point that bothers me is still not solved: recursive
local functions (ever tried it? *g*)

	do
          local foo
	  function foo(x)
	    if x<2 then return 1 end
	    return x*foo(x-1)	-- x*%foo(x-1) in std lua
	  end
	  print(foo(10))
	end

This did not work before and still breaks :-/

Ciao, ET.
diff -ru lua/src/lopcodes.h lua-upval/src/lopcodes.h
--- lua/src/lopcodes.h	Thu Jun 17 19:04:03 1999
+++ lua-upval/src/lopcodes.h	Tue Apr 11 19:17:28 2000
@@ -54,6 +54,8 @@
 CREATEARRAYW,/*	w	-		newarray(size = w)		*/
 CREATEARRAY,/*	b	-		newarray(size = b)		*/
 
+SETUPVALUE,/*	b	x		-		Closure[b]=x	*/
+
 SETLOCAL,/*	b	x		-		LOC[b]=x	*/
 
 SETGLOBALW,/*	w	x		-		VAR[CNST[w]]=x	*/
diff -ru lua/src/lparser.c lua-upval/src/lparser.c
--- lua/src/lparser.c	Thu Jun 17 19:04:03 1999
+++ lua-upval/src/lparser.c	Tue Apr 11 20:54:46 2000
@@ -34,7 +34,7 @@
 
 /* maximum number of upvalues */
 #ifndef MAXUPVALUES
-#define MAXUPVALUES 32  /* arbitrary limit (<256) */
+#define MAXUPVALUES 64  /* arbitrary limit (<256) */
 #endif
 
 
@@ -58,6 +58,7 @@
 typedef enum {
   VGLOBAL,  /* info is constant index of global name */
   VLOCAL,   /* info is stack index */
+  VUPVALUE, /* info is upvalue index */
   VDOT,     /* info is constant index of index name */
   VINDEXED, /* no info (table and index are on the stack) */
   VEXP      /* info is pc index of "nparam" of a call (or 0 if exp is closed) */
@@ -138,7 +139,6 @@
 static void ret (LexState *ls);
 static void statlist (LexState *ls);
 static void var_or_func (LexState *ls, vardesc *v);
-static void var_or_func_tail (LexState *ls, vardesc *v);
 
 
 
@@ -347,57 +347,37 @@
 }
 
 
-static int aux_localname (FuncState *fs, TaggedString *n) {
-  int i;
-  for (i=fs->nlocalvar-1; i >= 0; i--)
-    if (n == fs->localvar[i]) return i;  /* local var index */
-  return -1;  /* not found */
-}
-
-
-static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) {
-  FuncState *fs = prev ? ls->fs->prev : ls->fs;
-  int i = aux_localname(fs, n);
-  if (i >= 0) {  /* local value? */
-    var->k = VLOCAL;
-    var->info = i;
-  }
-  else {
-    FuncState *level = fs;
-    while ((level = level->prev) != NULL)  /* check shadowing */
-      if (aux_localname(level, n) >= 0)
-        luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str);
-    var->k = VGLOBAL;
-    var->info = string_constant(fs, n);
-  }
-}
-
-
-static int indexupvalue (LexState *ls, TaggedString *n) {
-  FuncState *fs = ls->fs;
-  vardesc v;
-  int i;
-  singlevar(ls, n, &v, 1);
-  for (i=0; i<fs->nupvalues; i++) {
-    if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info)
-      return i;
-  }
-  /* new one */
-  ++(fs->nupvalues);
-  checklimit(ls, fs->nupvalues, MAXUPVALUES, "upvalues");
-  fs->upvalues[i] = v;  /* i = fs->nupvalues - 1 */
-  return i;
-}
-
-
-static void pushupvalue (LexState *ls, TaggedString *n) {
-  if (ls->fs->prev == NULL)
-    luaX_syntaxerror(ls, "cannot access upvalue in main", n->str);
-  if (aux_localname(ls->fs, n) >= 0)
-    luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str);
-  code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1);
-}
-
+static void
+singlevar (LexState *ls, FuncState *fs, TaggedString *n, vardesc *var)
+{
+  int i;
+  if (!fs) {
+    var->k = VGLOBAL;
+    var->info = string_constant(ls->fs, n);
+    return;
+  }
+  for (i=fs->nlocalvar-1; i >= 0; i--)
+    if (fs->localvar[i] == n)
+      break;
+  if (i >= 0) {
+    var->k = VLOCAL;
+    var->info = i;
+    return;
+  }
+  singlevar(ls, fs->prev, n, var);
+  if (var->k != VGLOBAL) {
+    for (i=fs->nupvalues-1; i >= 0; i--)
+      if (fs->upvalues[i].k == var->k && fs->upvalues[i].info == var->info)
+	break;
+    if (i < 0) {
+      i = fs->nupvalues++;
+      checklimit(ls, fs->nupvalues, MAXUPVALUES, "upvalues");
+      fs->upvalues[i] = *var;
+    }
+    var->k = VUPVALUE;
+    var->info = i;
+  }
+}
 
 
 static void check_debugline (LexState *ls) {
@@ -480,6 +460,9 @@
     case VLOCAL:
       code_oparg(ls, PUSHLOCAL, var->info, 1);
       break;
+    case VUPVALUE:
+      code_oparg(ls, PUSHUPVALUE, var->info, 1);
+      break;
     case VGLOBAL:
       code_oparg(ls, GETGLOBAL, var->info, 1);
       break;
@@ -503,6 +486,9 @@
     case VLOCAL:
       code_oparg(ls, SETLOCAL, var->info, -1);
       break;
+    case VUPVALUE:
+      code_oparg(ls, SETUPVALUE, var->info, -1);
+      break;
     case VGLOBAL:
       code_oparg(ls, SETGLOBAL, var->info, -1);
       break;
@@ -782,16 +768,14 @@
       return 1;
     }
 
-    case NAME: case '%': {  /* stat -> func | ['%'] NAME assignment */
+    case NAME: {  /* stat -> func | NAME assignment */
       vardesc v;
       check_debugline(ls);
       var_or_func(ls, &v);
       if (v.k == VEXP) {  /* stat -> func */
-        if (v.info == 0)  /* is just an upper value? */
-          luaX_error(ls, "syntax error");
         close_exp(ls, v.info, 0);
       }
-      else {  /* stat -> ['%'] NAME assignment */
+      else {  /* stat -> NAME assignment */
         int left = assignment(ls, &v, 1);
         adjuststack(ls, left);  /* remove eventual 'garbage' left on stack */
       }
@@ -839,7 +823,7 @@
 static int funcname (LexState *ls, vardesc *v) {
   /* funcname -> NAME [':' NAME | '.' NAME] */
   int needself = 0;
-  singlevar(ls, str_checkname(ls), v, 0);
+  singlevar(ls, ls->fs, str_checkname(ls), v);
   if (ls->token == ':' || ls->token == '.') {
     needself = (ls->token == ':');
     next(ls);
@@ -1020,7 +1004,7 @@
       check(ls, ')');
       return;
 
-    case NAME: case '%':
+    case NAME:
       var_or_func(ls, v);
       return;
 
@@ -1065,29 +1049,17 @@
 
 
 static void var_or_func (LexState *ls, vardesc *v) {
-  /* var_or_func -> ['%'] NAME var_or_func_tail */
-  if (optional(ls, '%')) {  /* upvalue? */
-    pushupvalue(ls, str_checkname(ls));
-    v->k = VEXP;
-    v->info = 0;  /* closed expression */
-  }
-  else  /* variable name */
-    singlevar(ls, str_checkname(ls), v, 0);
-  var_or_func_tail(ls, v);
-}
-
-
-static void var_or_func_tail (LexState *ls, vardesc *v) {
+  singlevar(ls, ls->fs, str_checkname(ls), v);
   for (;;) {
     switch (ls->token) {
-      case '.':  /* var_or_func_tail -> '.' NAME */
+      case '.':  /* var_or_func -> '.' NAME */
         next(ls);
         lua_pushvar(ls, v);  /* 'v' must be on stack */
         v->k = VDOT;
         v->info = checkname(ls);
         break;
 
-      case '[':  /* var_or_func_tail -> '[' exp1 ']' */
+      case '[':  /* var_or_func -> '[' exp1 ']' */
         next(ls);
         lua_pushvar(ls, v);  /* 'v' must be on stack */
         exp1(ls);
@@ -1095,7 +1067,7 @@
         v->k = VINDEXED;
         break;
 
-      case ':':  /* var_or_func_tail -> ':' NAME funcparams */
+      case ':':  /* var_or_func -> ':' NAME funcparams */
         next(ls);
         lua_pushvar(ls, v);  /* 'v' must be on stack */
         code_oparg(ls, PUSHSELF, checkname(ls), 1);
@@ -1103,7 +1075,7 @@
         v->info = funcparams(ls, 1);
         break;
 
-      case '(': case STRING: case '{':  /* var_or_func_tail -> funcparams */
+      case '(': case STRING: case '{':  /* var_or_func -> funcparams */
         lua_pushvar(ls, v);  /* 'v' must be on stack */
         v->k = VEXP;
         v->info = funcparams(ls, 0);
@@ -1308,6 +1280,13 @@
           case VLOCAL:
             code_string(ls, ls->fs->localvar[v.info]);
             break;
+	  case VUPVALUE: {
+            FuncState *fs;
+            for (fs = ls->fs; v.k == VUPVALUE; fs = fs->prev)
+                v = fs->upvalues[v.info];
+            code_string(ls, fs->localvar[v.info]);
+            break;
+          }
           default:
             error_unexpected(ls);
         }
diff -ru lua/src/luac/opcode.h lua-upval/src/luac/opcode.h
--- lua/src/luac/opcode.h	Thu Mar 25 14:43:05 1999
+++ lua-upval/src/luac/opcode.h	Tue Apr 11 19:18:17 2000
@@ -27,6 +27,7 @@
 { "PUSHSELF", PUSHSELF, PUSHSELF, ARGS_B, -1, -1 },
 { "CREATEARRAYW", CREATEARRAYW, CREATEARRAY, ARGS_W, -1, -1 },
 { "CREATEARRAY", CREATEARRAY, CREATEARRAY, ARGS_B, -1, -1 },
+{ "SETUPVALUE", SETUPVALUE, SETUPVALUE, ARGS_B, -1, -1 },
 { "SETLOCAL", SETLOCAL, SETLOCAL, ARGS_B, -1, -1 },
 { "SETGLOBALW", SETGLOBALW, SETGLOBAL, ARGS_W, -1, -1 },
 { "SETGLOBAL", SETGLOBAL, SETGLOBAL, ARGS_B, -1, -1 },
diff -ru lua/src/luac/test.c lua-upval/src/luac/test.c
--- lua/src/luac/test.c	Fri Jul  2 21:34:26 1999
+++ lua-upval/src/luac/test.c	Tue Apr 11 19:19:47 2000
@@ -114,6 +114,7 @@
 	case GETDOTTED:		CHECK(1,1);		break;
 	case PUSHSELF:		CHECK(1,2);		break;
 	case CREATEARRAY:	CHECK(0,1);		break;
+	case SETUPVALUE:	CHECK(1,0);		break;
 	case SETLOCAL:		CHECK(1,0);		break;
 	case SETGLOBAL:		CHECK(1,0);		break;
 	case SETTABLEPOP:	CHECK(3,0);		break;
diff -ru lua/src/lvm.c lua-upval/src/lvm.c
--- lua/src/lvm.c	Tue Jun 22 22:37:23 1999
+++ lua-upval/src/lvm.c	Tue Apr 11 20:02:21 2000
@@ -420,6 +420,10 @@
         S->top++;
         break;
 
+      case SETUPVALUE: aux = *pc++;
+        cl->consts[aux+1] = *(--S->top);
+        break;
+
       case SETLOCAL: aux = *pc++;
         *((S->stack+base) + aux) = *(--S->top);
         break;