Browse Source

first implementation for type names

Roberto Ierusalimschy 24 năm trước cách đây
mục cha
commit
a53d9b66ca
15 tập tin đã thay đổi với 295 bổ sung233 xóa
  1. 54 6
      lapi.c
  2. 20 8
      lauxlib.c
  3. 2 1
      lauxlib.h
  4. 41 12
      lbaselib.c
  5. 4 4
      ldebug.c
  6. 9 6
      lgc.c
  7. 90 151
      liolib.c
  8. 1 7
      lobject.c
  9. 1 5
      lobject.h
  10. 2 1
      lstate.c
  11. 2 1
      lstate.h
  12. 3 1
      ltable.c
  13. 50 26
      ltm.c
  14. 8 2
      ltm.h
  15. 8 2
      lua.h

+ 54 - 6
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 1.118 2001/01/19 13:20:30 roberto Exp roberto $
+** $Id: lapi.c,v 1.119 2001/01/24 15:45:33 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -132,16 +132,27 @@ LUA_API int lua_type (lua_State *L, int index) {
   return i;
 }
 
+
 LUA_API const char *lua_typename (lua_State *L, int t) {
   const char *s;
   LUA_ENTRY;
-  UNUSED(L);
-  s = (t == LUA_TNONE) ? "no value" : luaO_typenames[t];
+  s = (t == LUA_TNONE) ? "no value" : basictypename(G(L), t);
   LUA_EXIT;
   return s;
 }
 
 
+LUA_API const char *lua_xtype (lua_State *L, int index) {
+  StkId o;
+  const char *type;
+  LUA_ENTRY;
+  o = luaA_indexAcceptable(L, index);
+  type = (o == NULL) ? "no value" : luaT_typename(G(L), o);
+  LUA_EXIT;
+  return type;
+}
+
+
 LUA_API int lua_iscfunction (lua_State *L, int index) {
   StkId o;
   int i;
@@ -553,9 +564,46 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) {
 ** miscellaneous functions
 */
 
-LUA_API void lua_settag (lua_State *L, int tag) {
+LUA_API int lua_newtype (lua_State *L, const char *name, int basictype) {
+  int tag;
   LUA_ENTRY;
-  luaT_realtag(L, tag);
+  if (basictype != LUA_TNONE &&
+      basictype != LUA_TTABLE &&
+      basictype != LUA_TUSERDATA)
+    luaO_verror(L, "invalid basic type (%d) for new type", basictype);
+  tag = luaT_newtag(L, name, basictype);
+  if (tag == LUA_TNONE)
+    luaO_verror(L, "type name '%.30s' already exists", name);
+  LUA_EXIT;
+  return tag;
+}
+
+
+LUA_API int lua_type2tag (lua_State *L, const char *name) {
+  int tag;
+  const TObject *v;
+  LUA_ENTRY;
+  v = luaH_getstr(G(L)->type2tag, luaS_new(L, name));
+  if (ttype(v) == LUA_TNIL)
+    tag = LUA_TNONE;
+  else {
+    lua_assert(ttype(v) == LUA_TNUMBER);
+    tag = nvalue(v);
+  }
+  LUA_EXIT;
+  return tag;
+}
+
+
+LUA_API void lua_settag (lua_State *L, int tag) {
+  int basictype;
+  LUA_ENTRY;
+  if (tag < 0 || tag >= G(L)->ntag)
+    luaO_verror(L, "%d is not a valid tag", tag);
+  basictype = G(L)->TMtable[tag].basictype;
+  if (basictype != LUA_TNONE && basictype != ttype(L->top-1))
+    luaO_verror(L, "tag %d can only be used for type '%.20s'", tag,
+                basictypename(G(L), basictype));
   switch (ttype(L->top-1)) {
     case LUA_TTABLE:
       hvalue(L->top-1)->htag = tag;
@@ -565,7 +613,7 @@ LUA_API void lua_settag (lua_State *L, int tag) {
       break;
     default:
       luaO_verror(L, "cannot change the tag of a %.20s",
-                  luaO_typename(L->top-1));
+                  luaT_typename(G(L), L->top-1));
   }
   LUA_EXIT;
 }

+ 20 - 8
lauxlib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.c,v 1.43 2000/10/30 13:07:48 roberto Exp roberto $
+** $Id: lauxlib.c,v 1.44 2000/12/04 18:33:40 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -40,14 +40,18 @@ LUALIB_API void luaL_argerror (lua_State *L, int narg, const char *extramsg) {
 }
 
 
-static void type_error (lua_State *L, int narg, int t) {
-  char buff[50];
-  sprintf(buff, "%.8s expected, got %.8s", lua_typename(L, t),
-                                           lua_typename(L, lua_type(L, narg)));
+static void type_error (lua_State *L, int narg, const char *tname) {
+  char buff[80];
+  sprintf(buff, "%.25s expected, got %.25s", tname, lua_xtype(L, narg));
   luaL_argerror(L, narg, buff);
 }
 
 
+static void tag_error (lua_State *L, int narg, int tag) {
+  type_error(L, narg, lua_typename(L, tag)); 
+}
+
+
 LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
   if (space > lua_stackspace(L))
     luaL_verror(L, "stack overflow (%.30s)", mes);
@@ -56,7 +60,7 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
 
 LUALIB_API void luaL_checktype(lua_State *L, int narg, int t) {
   if (lua_type(L, narg) != t)
-    type_error(L, narg, t);
+    tag_error(L, narg, t);
 }
 
 
@@ -66,9 +70,17 @@ LUALIB_API void luaL_checkany (lua_State *L, int narg) {
 }
 
 
+LUALIB_API void *luaL_check_userdata (lua_State *L, int narg,
+                                      const char *name) {
+  if (strcmp(lua_xtype(L, narg), name) != 0)
+    type_error(L, narg, name);
+  return lua_touserdata(L, narg);
+}
+
+
 LUALIB_API const char *luaL_check_lstr (lua_State *L, int narg, size_t *len) {
   const char *s = lua_tostring(L, narg);
-  if (!s) type_error(L, narg, LUA_TSTRING);
+  if (!s) tag_error(L, narg, LUA_TSTRING);
   if (len) *len = lua_strlen(L, narg);
   return s;
 }
@@ -87,7 +99,7 @@ LUALIB_API const char *luaL_opt_lstr (lua_State *L, int narg, const char *def, s
 LUALIB_API lua_Number luaL_check_number (lua_State *L, int narg) {
   lua_Number d = lua_tonumber(L, narg);
   if (d == 0 && !lua_isnumber(L, narg))  /* avoid extra test when d is not 0 */
-    type_error(L, narg, LUA_TNUMBER);
+    tag_error(L, narg, LUA_TNUMBER);
   return d;
 }
 

+ 2 - 1
lauxlib.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lauxlib.h,v 1.30 2000/10/30 12:38:50 roberto Exp roberto $
+** $Id: lauxlib.h,v 1.31 2000/12/04 18:33:40 roberto Exp roberto $
 ** Auxiliary functions for building Lua libraries
 ** See Copyright Notice in lua.h
 */
@@ -36,6 +36,7 @@ LUALIB_API lua_Number luaL_opt_number (lua_State *L, int nArg, lua_Number def);
 LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg);
 LUALIB_API void luaL_checktype (lua_State *L, int narg, int t);
 LUALIB_API void luaL_checkany (lua_State *L, int narg);
+LUALIB_API void *luaL_check_userdata (lua_State *L, int narg, const char *name);
 
 LUALIB_API void luaL_verror (lua_State *L, const char *fmt, ...);
 LUALIB_API int luaL_findstring (const char *name, const char *const list[]);

+ 41 - 12
lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.17 2000/11/06 13:45:18 roberto Exp roberto $
+** $Id: lbaselib.c,v 1.18 2001/01/10 16:58:11 roberto Exp roberto $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
@@ -128,6 +128,26 @@ static int luaB_getglobal (lua_State *L) {
   return 1;
 }
 
+
+/* auxiliary function to get `tags' */
+static int gettag (lua_State *L, int narg) {
+  switch (lua_type(L, narg)) {
+    case LUA_TNUMBER:
+      return (int)lua_tonumber(L, narg);
+    case LUA_TSTRING: {
+      const char *name = lua_tostring(L, narg);
+      int tag = lua_type2tag(L, name);
+      if (tag == LUA_TNONE)
+        luaL_verror(L, "'%.30s' is not a valid type name", name);
+      return tag;
+    }
+    default:
+      luaL_argerror(L, narg, "tag or type name expected");
+      return 0;  /* to avoid warnings */
+  }
+}
+
+
 static int luaB_tag (lua_State *L) {
   luaL_checkany(L, 1);
   lua_pushnumber(L, lua_tag(L, 1));
@@ -137,18 +157,18 @@ static int luaB_tag (lua_State *L) {
 static int luaB_settag (lua_State *L) {
   luaL_checktype(L, 1, LUA_TTABLE);
   lua_pushvalue(L, 1);  /* push table */
-  lua_settag(L, luaL_check_int(L, 2));
+  lua_settag(L, gettag(L, 2));
   return 1;  /* return table */
 }
 
-static int luaB_newtag (lua_State *L) {
-  lua_pushnumber(L, lua_newtag(L));
+static int luaB_newtype (lua_State *L) {
+  const char *name = luaL_opt_string(L, 1, NULL);
+  lua_pushnumber(L, lua_newtype(L, name, LUA_TTABLE));
   return 1;
 }
 
 static int luaB_copytagmethods (lua_State *L) {
-  lua_pushnumber(L, lua_copytagmethods(L, luaL_check_int(L, 1),
-                                          luaL_check_int(L, 2)));
+  lua_pushnumber(L, lua_copytagmethods(L, gettag(L, 1), gettag(L, 2)));
   return 1;
 }
 
@@ -178,7 +198,7 @@ static int luaB_rawset (lua_State *L) {
 }
 
 static int luaB_settagmethod (lua_State *L) {
-  int tag = luaL_check_int(L, 1);
+  int tag = gettag(L, 1);
   const char *event = luaL_check_string(L, 2);
   luaL_arg_check(L, lua_isfunction(L, 3) || lua_isnil(L, 3), 3,
                  "function or nil expected");
@@ -192,7 +212,7 @@ static int luaB_settagmethod (lua_State *L) {
 
 
 static int luaB_gettagmethod (lua_State *L) {
-  int tag = luaL_check_int(L, 1);
+  int tag = gettag(L, 1);
   const char *event = luaL_check_string(L, 2);
   if (strcmp(event, "gc") == 0)
     lua_error(L, "deprecated use: cannot get the `gc' tag method from Lua");
@@ -221,6 +241,13 @@ static int luaB_type (lua_State *L) {
 }
 
 
+static int luaB_xtype (lua_State *L) {
+  luaL_checkany(L, 1);
+  lua_pushstring(L, lua_xtype(L, 1));
+  return 1;
+}
+
+
 static int luaB_next (lua_State *L) {
   luaL_checktype(L, 1, LUA_TTABLE);
   lua_settop(L, 2);  /* create a 2nd argument if there isn't one */
@@ -619,13 +646,14 @@ static const struct luaL_reg base_funcs[] = {
   {"getglobal", luaB_getglobal},
   {"gettagmethod", luaB_gettagmethod},
   {"globals", luaB_globals},
-  {"newtag", luaB_newtag},
+  {"newtype", luaB_newtype},
+  {"newtag", luaB_newtype},  /* for compatibility 4.0 */
   {"next", luaB_next},
   {"print", luaB_print},
   {"rawget", luaB_rawget},
   {"rawset", luaB_rawset},
-  {"rawgettable", luaB_rawget},  /* for compatibility */
-  {"rawsettable", luaB_rawset},  /* for compatibility */
+  {"rawgettable", luaB_rawget},  /* for compatibility 3.2 */
+  {"rawsettable", luaB_rawset},  /* for compatibility 3.2 */
   {"setglobal", luaB_setglobal},
   {"settag", luaB_settag},
   {"settagmethod", luaB_settagmethod},
@@ -637,7 +665,8 @@ static const struct luaL_reg base_funcs[] = {
   {"getn", luaB_getn},
   {"sort", luaB_sort},
   {"tinsert", luaB_tinsert},
-  {"tremove", luaB_tremove}
+  {"tremove", luaB_tremove},
+  {"xtype", luaB_xtype},
 };
 
 

+ 4 - 4
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 1.54 2001/01/19 13:20:30 roberto Exp roberto $
+** $Id: ldebug.c,v 1.55 2001/01/24 15:45:33 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -466,7 +466,7 @@ static const char *getfuncname (lua_State *L, StkId f, const char **name) {
 void luaG_typeerror (lua_State *L, StkId o, const char *op) {
   const char *name;
   const char *kind = getobjname(L, o, &name);
-  const char *t = luaO_typename(o);
+  const char *t = luaT_typename(G(L), o);
   if (kind)
     luaO_verror(L, "attempt to %.30s %.20s `%.40s' (a %.10s value)",
                 op, kind, name, t);
@@ -483,8 +483,8 @@ void luaG_binerror (lua_State *L, StkId p1, int t, const char *op) {
 
 
 void luaG_ordererror (lua_State *L, StkId top) {
-  const char *t1 = luaO_typename(top-2);
-  const char *t2 = luaO_typename(top-1);
+  const char *t1 = luaT_typename(G(L), top-2);
+  const char *t2 = luaT_typename(G(L), top-1);
   if (t1[2] == t2[2])
     luaO_verror(L, "attempt to compare two %.10s values", t1);
   else

+ 9 - 6
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 1.77 2001/01/19 13:20:30 roberto Exp roberto $
+** $Id: lgc.c,v 1.78 2001/01/22 18:01:38 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -108,11 +108,13 @@ static void marklock (global_State *G, GCState *st) {
 
 
 static void marktagmethods (global_State *G, GCState *st) {
-  int e;
-  for (e=0; e<TM_N; e++) {
-    int t;
-    for (t=0; t<G->ntag; t++) {
-      Closure *cl = luaT_gettm(G, t, e);
+  int t;
+  for (t=0; t<G->ntag; t++) {
+    struct TM *tm = &G->TMtable[t];
+    int e;
+    if (tm->name) strmark(tm->name);
+    for (e=0; e<TM_N; e++) {
+      Closure *cl = tm->method[e];
       if (cl) markclosure(st, cl);
     }
   }
@@ -126,6 +128,7 @@ static void markall (lua_State *L) {
   marktagmethods(G(L), &st);  /* mark tag methods */
   markstacks(L, &st); /* mark all stacks */
   marklock(G(L), &st); /* mark locked objects */
+  marktable(&st, G(L)->type2tag);
   for (;;) {  /* mark tables and closures */
     if (st.cmark) {
       int i;

+ 90 - 151
liolib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: liolib.c,v 1.98 2001/01/11 18:59:03 roberto Exp roberto $
+** $Id: liolib.c,v 1.99 2001/01/18 15:59:09 roberto Exp roberto $
 ** Standard I/O (and system) library
 ** See Copyright Notice in lua.h
 */
@@ -32,7 +32,7 @@
 #define LC_MONETARY	0
 #define LC_NUMERIC	0
 #define LC_TIME		0
-#define strerror(e)	"generic I/O error"
+#define strerror(e)	"I/O error"
 #define errno		(-1)
 #endif
 
@@ -53,13 +53,7 @@ int pclose(); */
 #define OUTFILE 1
 #define NOFILE	2
 
-
-typedef struct IOCtrl {
-  int ref[2];  /* ref for strings _INPUT/_OUTPUT */
-  int iotag;    /* tag for file handles */
-  int closedtag;  /* tag for closed handles */
-} IOCtrl;
-
+#define FILEHANDLE	"FileHandle"
 
 
 static const char *const filenames[] = {"_INPUT", "_OUTPUT"};
@@ -74,7 +68,7 @@ static int pushresult (lua_State *L, int i) {
     lua_pushnil(L);
     lua_pushstring(L, strerror(errno));
     lua_pushnumber(L, errno);
-    return 3;;
+    return 3;
   }
 }
 
@@ -86,83 +80,77 @@ static int pushresult (lua_State *L, int i) {
 */
 
 
-static FILE *gethandle (lua_State *L, IOCtrl *ctrl, int f) {
-  FILE *p = (FILE *)lua_touserdata(L, f);
-  if (p != NULL) {  /* is `f' a userdata ? */
-    int ftag = lua_tag(L, f);
-    if (ftag == ctrl->iotag)  /* does it have the correct tag? */
-      return p;
-    else if (ftag == ctrl->closedtag)
-      lua_error(L, "cannot access a closed file");
-    /* else go through */
-  }
-  return NULL;
-}
+#define checkfile(L,f)	(strcmp(lua_xtype(L,(f)), FILEHANDLE) == 0)
 
 
-static FILE *getnonullfile (lua_State *L, IOCtrl *ctrl, int arg) {
-  FILE *f = gethandle(L, ctrl, arg);
-  luaL_arg_check(L, f, arg, "invalid file handle");
-  return f;
+static FILE *getopthandle (lua_State *L, int inout) {
+  FILE *p = (FILE *)lua_touserdata(L, 1);
+  if (p != NULL) {  /* is it a userdata ? */
+    if (!checkfile(L,1)) {
+      if (strcmp(lua_xtype(L, 1), "ClosedFileHandle") == 0)
+        luaL_argerror(L, 1, "file is closed");
+      else
+        luaL_argerror(L, 1, "(invalid value)");
+    }
+    lua_remove(L, 1);  /* remove it from stack */
+  }
+  else if (inout != NOFILE) {  /* try global value */
+    lua_getglobal(L, filenames[inout]);
+    if (!checkfile(L,-1))
+      luaL_verror(L, "global variable `%.10s' is not a valid file handle",
+                  filenames[inout]);
+    p = (FILE *)lua_touserdata(L, -1);
+    lua_pop(L, 1);  /* remove global value from stack */
+  }
+  return p;
 }
 
 
-static FILE *getfilebyref (lua_State *L, IOCtrl *ctrl, int inout) {
-  FILE *f;
-  lua_getglobals(L);
-  lua_getref(L, ctrl->ref[inout]);
-  lua_rawget(L, -2);
-  f = gethandle(L, ctrl, -1);
-  if (f == NULL)
-    luaL_verror(L, "global variable `%.10s' is not a file handle",
-                filenames[inout]);
-  return f;
+static void pushfile (lua_State *L, FILE *f) {
+  lua_pushusertag(L, f, lua_type2tag(L, FILEHANDLE));
 }
 
 
-static void setfilebyname (lua_State *L, IOCtrl *ctrl, FILE *f,
-                           const char *name) {
-  lua_pushusertag(L, f, ctrl->iotag);
+static void setfilebyname (lua_State *L, FILE *f, const char *name) {
+  pushfile(L, f);
   lua_setglobal(L, name);
 }
 
 
-#define setfile(L,ctrl,f,inout)	(setfilebyname(L,ctrl,f,filenames[inout]))
+#define setfile(L,f,inout)	(setfilebyname(L,f,filenames[inout]))
 
 
-static int setreturn (lua_State *L, IOCtrl *ctrl, FILE *f, int inout) {
+static int setreturn (lua_State *L, FILE *f, int inout) {
   if (f == NULL)
     return pushresult(L, 0);
   else {
     if (inout != NOFILE)
-      setfile(L, ctrl, f, inout);
-    lua_pushusertag(L, f, ctrl->iotag);
+      setfile(L, f, inout);
+    pushfile(L, f);
     return 1;
   }
 }
 
 
-static int closefile (lua_State *L, IOCtrl *ctrl, FILE *f) {
+static int closefile (lua_State *L, FILE *f) {
   if (f == stdin || f == stdout || f == stderr)
     return 1;
   else {
-    lua_pushusertag(L, f, ctrl->iotag);
-    lua_settag(L, ctrl->closedtag);
+    pushfile(L, f);
+    lua_settag(L, lua_type2tag(L, "ClosedFileHandle"));
     return (CLOSEFILE(L, f) == 0);
   }
 }
 
 
 static int io_close (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  lua_pop(L, 1);  /* remove upvalue */
-  return pushresult(L, closefile(L, ctrl, getnonullfile(L, ctrl, 1)));
+  FILE *f = (FILE *)luaL_check_userdata(L, 1, FILEHANDLE);
+  return pushresult(L, closefile(L, f));
 }
 
 
 static int file_collect (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  FILE *f = getnonullfile(L, ctrl, 1);
+  FILE *f = (FILE *)luaL_check_userdata(L, 1, FILEHANDLE);
   if (f != stdin && f != stdout && f != stderr)
     CLOSEFILE(L, f);
   return 0;
@@ -170,36 +158,30 @@ static int file_collect (lua_State *L) {
 
 
 static int io_open (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  FILE *f;
-  lua_pop(L, 1);  /* remove upvalue */
-  f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2));
-  return setreturn(L, ctrl, f, NOFILE);
+  FILE *f = fopen(luaL_check_string(L, 1), luaL_check_string(L, 2));
+  return setreturn(L, f, NOFILE);
 }
 
 
 static int io_tmpfile (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  return setreturn(L, ctrl, tmpfile(), NOFILE);
+  return setreturn(L, tmpfile(), NOFILE);
 }
 
 
 
 static int io_fromto (lua_State *L, int inout, const char *mode) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
   FILE *current;
-  lua_pop(L, 1);  /* remove upvalue */
   if (lua_isnull(L, 1)) {
-    closefile(L, ctrl, getfilebyref(L, ctrl, inout));
+    closefile(L, getopthandle(L, inout));
     current = (inout == 0) ? stdin : stdout;    
   }
-  else if (lua_tag(L, 1) == ctrl->iotag)  /* deprecated option */
+  else if (checkfile(L, 1))  /* deprecated option */
     current = (FILE *)lua_touserdata(L, 1);
   else {
     const char *s = luaL_check_string(L, 1);
     current = (*s == '|') ? popen(s+1, mode) : fopen(s, mode);
   }
-  return setreturn(L, ctrl, current, inout);
+  return setreturn(L, current, inout);
 }
 
 
@@ -214,11 +196,8 @@ static int io_writeto (lua_State *L) {
 
 
 static int io_appendto (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  FILE *current;
-  lua_pop(L, 1);  /* remove upvalue */
-  current = fopen(luaL_check_string(L, 1), "a");
-  return setreturn(L, ctrl, current, OUTFILE);
+  FILE *current = fopen(luaL_check_string(L, 1), "a");
+  return setreturn(L, current, OUTFILE);
 }
 
 
@@ -315,31 +294,24 @@ static int read_chars (lua_State *L, FILE *f, size_t n) {
 
 
 static int io_read (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  int lastarg = lua_gettop(L) - 1;
-  int firstarg = 1;
+  FILE *f = getopthandle(L, INFILE);
+  int nargs = lua_gettop(L);
   int success;
-  FILE *f = gethandle(L, ctrl, firstarg);
   int n;
-  if (f) firstarg++;
-  else f = getfilebyref(L, ctrl, INFILE);  /* get _INPUT */
-  lua_pop(L, 1);
-  if (firstarg > lastarg) {  /* no arguments? */
-    lua_settop(L, 0);  /* erase upvalue and other eventual garbage */
-    firstarg = lastarg = 1;  /* correct indices */
-    lua_pushliteral(L, "*l");  /* push default argument */
+  if (nargs == 0) {  /* no arguments? */
+    success = read_line(L, f);
+    n = 2;  /* will return n-1 results */
   }
-  else  /* ensure stack space for all results and for auxlib's buffer */
-    luaL_checkstack(L, lastarg-firstarg+1+LUA_MINSTACK, "too many arguments");
-  success = 1;
-  for (n = firstarg; n<=lastarg && success; n++) {
-    if (lua_isnumber(L, n))
-      success = read_chars(L, f, (size_t)lua_tonumber(L, n));
-    else {
+  else {  /* ensure stack space for all results and for auxlib's buffer */
+    luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
+    success = 1;
+    for (n = 1; n<=nargs && success; n++) {
       const char *p = luaL_check_string(L, n);
       if (p[0] != '*') {
-        lua_error(L, "read patterns are deprecated");
-        success = 0;  /* to avoid warnings */
+        if (lua_isnumber(L, n))
+          success = read_chars(L, f, (size_t)lua_tonumber(L, n));
+        else
+          lua_error(L, "read patterns are deprecated");
       }
       else {
         switch (p[1]) {
@@ -367,21 +339,18 @@ static int io_read (lua_State *L) {
     lua_pop(L, 1);  /* remove last result */
     lua_pushnil(L);  /* push nil instead */
   }
-  return n - firstarg;
+  return n - 1;
 }
 
 /* }====================================================== */
 
 
 static int io_write (lua_State *L) {
-  int lastarg = lua_gettop(L) - 1;
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  int arg = 1;
+  FILE *f = getopthandle(L, OUTFILE);
+  int nargs = lua_gettop(L);
+  int arg;
   int status = 1;
-  FILE *f = gethandle(L, ctrl, arg);
-  if (f) arg++;
-  else f = getfilebyref(L, ctrl, OUTFILE);  /* get _OUTPUT */
-  for (; arg <=  lastarg; arg++) {
+  for (arg=1; arg<=nargs; arg++) {
     if (lua_type(L, arg) == LUA_TNUMBER) {  /* LUA_NUMBER */
       /* optimization: could be done exactly as for strings */
       status = status && fprintf(f, "%.16g", lua_tonumber(L, arg)) > 0;
@@ -400,14 +369,9 @@ static int io_write (lua_State *L) {
 static int io_seek (lua_State *L) {
   static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
   static const char *const modenames[] = {"set", "cur", "end", NULL};
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  FILE *f;
-  int op;
-  long offset;
-  lua_pop(L, 1);  /* remove upvalue */
-  f = getnonullfile(L, ctrl, 1);
-  op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames);
-  offset = luaL_opt_long(L, 3, 0);
+  FILE *f = (FILE *)luaL_check_userdata(L, 1, FILEHANDLE);
+  int op = luaL_findstring(luaL_opt_string(L, 2, "cur"), modenames);
+  long offset = luaL_opt_long(L, 3, 0);
   luaL_arg_check(L, op != -1, 2, "invalid mode");
   op = fseek(f, offset, mode[op]);
   if (op)
@@ -420,10 +384,7 @@ static int io_seek (lua_State *L) {
 
 
 static int io_flush (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_touserdata(L, -1);
-  FILE *f;
-  lua_pop(L, 1);  /* remove upvalue */
-  f = gethandle(L, ctrl, 1);
+  FILE *f = getopthandle(L, NOFILE);
   luaL_arg_check(L, f || lua_isnull(L, 1), 1, "invalid file handle");
   return pushresult(L, fflush(f) == 0);
 }
@@ -686,66 +647,44 @@ static int errorfb (lua_State *L) {
 
 
 static const struct luaL_reg iolib[] = {
-  {LUA_ERRORMESSAGE, errorfb},
+  {"appendto",  io_appendto},
   {"clock",     io_clock},
+  {"closefile", io_close},
   {"date",      io_date},
   {"debug",     io_debug},
   {"difftime",  io_difftime},
   {"execute",   io_execute},
   {"exit",      io_exit},
-  {"getenv",    io_getenv},
-  {"remove",    io_remove},
-  {"rename",    io_rename},
-  {"setlocale", io_setloc},
-  {"time",      io_time},
-  {"tmpname",   io_tmpname}
-};
-
-
-static const struct luaL_reg iolibtag[] = {
-  {"appendto",  io_appendto},
-  {"closefile", io_close},
   {"flush",     io_flush},
+  {"getenv",    io_getenv},
   {"openfile",  io_open},
   {"read",      io_read},
   {"readfrom",  io_readfrom},
+  {"remove",    io_remove},
+  {"rename",    io_rename},
   {"seek",      io_seek},
+  {"setlocale", io_setloc},
+  {"time",      io_time},
   {"tmpfile",   io_tmpfile},
+  {"tmpname",   io_tmpname},
   {"write",     io_write},
-  {"writeto",   io_writeto}
+  {"writeto",   io_writeto},
+  {LUA_ERRORMESSAGE, errorfb}
 };
 
 
-static void openwithcontrol (lua_State *L) {
-  IOCtrl *ctrl = (IOCtrl *)lua_newuserdata(L, sizeof(IOCtrl));
-  unsigned int i;
-  ctrl->iotag = lua_newtag(L);
-  ctrl->closedtag = lua_newtag(L);
-  for (i=0; i<sizeof(iolibtag)/sizeof(iolibtag[0]); i++) {
-    /* put `ctrl' as upvalue for these functions */
-    lua_pushvalue(L, -1);
-    lua_pushcclosure(L, iolibtag[i].func, 1);
-    lua_setglobal(L, iolibtag[i].name);
-  }
-  /* create references to variable names */
-  lua_pushstring(L, filenames[INFILE]);
-  ctrl->ref[INFILE] = lua_ref(L, 1);
-  lua_pushstring(L, filenames[OUTFILE]);
-  ctrl->ref[OUTFILE] = lua_ref(L, 1);
-  /* predefined file handles */
-  setfile(L, ctrl, stdin, INFILE);
-  setfile(L, ctrl, stdout, OUTFILE);
-  setfilebyname(L, ctrl, stdin, "_STDIN");
-  setfilebyname(L, ctrl, stdout, "_STDOUT");
-  setfilebyname(L, ctrl, stderr, "_STDERR");
-  /* close files when collected */
-  lua_pushcclosure(L, file_collect, 1);  /* pops `ctrl' from stack */
-  lua_settagmethod(L, ctrl->iotag, "gc");
-}
-
-
 LUALIB_API void lua_iolibopen (lua_State *L) {
+  int iotag = lua_newtype(L, FILEHANDLE, LUA_TUSERDATA);
+  lua_newtype(L, "ClosedFileHandle", LUA_TUSERDATA);
   luaL_openl(L, iolib);
-  openwithcontrol(L);
+  /* predefined file handles */
+  setfile(L, stdin, INFILE);
+  setfile(L, stdout, OUTFILE);
+  setfilebyname(L, stdin, "_STDIN");
+  setfilebyname(L, stdout, "_STDOUT");
+  setfilebyname(L, stderr, "_STDERR");
+  /* close files when collected */
+  lua_pushcfunction(L, file_collect);
+  lua_settagmethod(L, iotag, "gc");
 }
 

+ 1 - 7
lobject.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.c,v 1.59 2001/01/19 13:20:30 roberto Exp roberto $
+** $Id: lobject.c,v 1.60 2001/01/24 15:45:33 roberto Exp roberto $
 ** Some generic functions over Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -22,12 +22,6 @@
 const TObject luaO_nilobject = {LUA_TNIL, {NULL}};
 
 
-const char *const luaO_typenames[] = {
-  "userdata", "nil", "number", "string", "table", "function"
-};
-
-
-
 /*
 ** returns smaller power of 2 larger than `n' (minimum is MINPOWER2) 
 */

+ 1 - 5
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 1.86 2001/01/18 15:59:09 roberto Exp roberto $
+** $Id: lobject.h,v 1.87 2001/01/19 13:20:30 roberto Exp roberto $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -212,10 +212,6 @@ typedef struct CallInfo {
 
 
 extern const TObject luaO_nilobject;
-extern const char *const luaO_typenames[];
-
-
-#define luaO_typename(o)	(luaO_typenames[ttype(o)])
 
 
 luint32 luaO_power2 (luint32 n);

+ 2 - 1
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 1.52 2001/01/22 18:01:38 roberto Exp roberto $
+** $Id: lstate.c,v 1.53 2001/01/24 15:45:33 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -86,6 +86,7 @@ static void f_luaopen (lua_State *L, void *ud) {
     G(L)->nblocks = sizeof(lua_State) + sizeof(global_State);
     luaD_init(L, so->stacksize);  /* init stack */
     L->gt = luaH_new(L, 10);  /* table of globals */
+    G(L)->type2tag = luaH_new(L, 10);
     luaS_init(L);
     luaX_init(L);
     luaT_init(L);

+ 2 - 1
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 1.45 2001/01/22 18:01:38 roberto Exp roberto $
+** $Id: lstate.h,v 1.46 2001/01/24 15:45:33 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -73,6 +73,7 @@ typedef struct global_State {
   Hash *roottable;  /* list of all tables */
   stringtable strt;  /* hash table for strings */
   stringtable udt;   /* hash table for udata */
+  Hash *type2tag;  /* hash table from type names to tags */
   struct TM *TMtable;  /* table for tag methods */
   int sizeTM;  /* size of TMtable */
   int ntag;  /* number of tags in TMtable */

+ 3 - 1
ltable.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltable.c,v 1.65 2001/01/19 13:20:30 roberto Exp roberto $
+** $Id: ltable.c,v 1.66 2001/01/24 15:45:33 roberto Exp roberto $
 ** Lua tables (hash)
 ** See Copyright Notice in lua.h
 */
@@ -236,6 +236,7 @@ static TObject *newkey (lua_State *L, Hash *t, Node *mp, const TObject *key) {
       othern->next = n;  /* redo the chain with `n' in place of `mp' */
       *n = *mp;  /* copy colliding node into free pos. (mp->next also goes) */
       mp->next = NULL;  /* now `mp' is free */
+      setnilvalue(&mp->val);
     }
     else {  /* colliding node is in its own main position */
       /* new node will go into free position */
@@ -245,6 +246,7 @@ static TObject *newkey (lua_State *L, Hash *t, Node *mp, const TObject *key) {
     }
   }
   setobj(&mp->key, key);
+  lua_assert(ttype(&mp->val) == LUA_TNIL);
   for (;;) {  /* correct `firstfree' */
     if (ttype(&t->firstfree->key) == LUA_TNIL)
       return &mp->val;  /* OK; table still has a free place */

+ 50 - 26
ltm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.c,v 1.61 2001/01/19 13:20:30 roberto Exp roberto $
+** $Id: ltm.c,v 1.62 2001/01/24 15:45:33 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -14,6 +14,8 @@
 #include "lmem.h"
 #include "lobject.h"
 #include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
 #include "ltm.h"
 
 
@@ -65,32 +67,38 @@ int luaT_validevent (int t, int e) {  /* ORDER LUA_T */
 }
 
 
-static void init_entry (lua_State *L, int tag) {
-  int i;
-  for (i=0; i<TM_N; i++)
-    luaT_gettm(G(L), tag, i) = NULL;
-  G(L)->TMtable[tag].collected = NULL;
-}
-
-
 void luaT_init (lua_State *L) {
-  int t;
-  G(L)->TMtable = luaM_newvector(L, NUM_TAGS+2, struct TM);
-  G(L)->sizeTM = NUM_TAGS+2;
-  G(L)->ntag = NUM_TAGS;
-  for (t=0; t<G(L)->ntag; t++)
-    init_entry(L, t);
+  static const char *const typenames[NUM_TAGS] = {
+    "userdata", "nil", "number", "string", "table", "function"
+  };
+  int i;
+  for (i=0; i<NUM_TAGS; i++)
+    luaT_newtag(L, typenames[i], i);
 }
 
 
-LUA_API int lua_newtag (lua_State *L) {
+int luaT_newtag (lua_State *L, const char *name, int basictype) {
   int tag;
-  LUA_ENTRY;
+  int i;
+  TString *ts;
   luaM_growvector(L, G(L)->TMtable, G(L)->ntag, G(L)->sizeTM, struct TM,
                   MAX_INT, "tag table overflow");
-  init_entry(L, G(L)->ntag);
-  tag = G(L)->ntag++;
-  LUA_EXIT;
+  tag = G(L)->ntag;
+  if (name == NULL)
+    ts = NULL;
+  else {
+    TObject *v;
+    ts = luaS_new(L, name);
+    v = luaH_setstr(L, G(L)->type2tag, ts);
+    if (ttype(v) != LUA_TNIL) return LUA_TNONE;  /* invalid name */
+    setnvalue(v, tag);
+  }
+  for (i=0; i<TM_N; i++)
+    luaT_gettm(G(L), tag, i) = NULL;
+  G(L)->TMtable[tag].collected = NULL;
+  G(L)->TMtable[tag].name = ts;
+  G(L)->TMtable[tag].basictype = basictype;
+  G(L)->ntag++;
   return tag;
 }
 
@@ -100,11 +108,6 @@ static void checktag (lua_State *L, int tag) {
     luaO_verror(L, "%d is not a valid tag", tag);
 }
 
-void luaT_realtag (lua_State *L, int tag) {
-  if (!validtag(G(L), tag))
-    luaO_verror(L, "tag %d was not created by `newtag'", tag);
-}
-
 
 LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom) {
   int e;
@@ -130,6 +133,27 @@ int luaT_tag (const TObject *o) {
 }
 
 
+const char *luaT_typename (global_State *G, const TObject *o) {
+  int t = ttype(o);
+  int tag;
+  TString *ts;
+  switch (t) {
+    case LUA_TUSERDATA:
+      tag = tsvalue(o)->u.d.tag;
+      break;
+    case LUA_TTABLE:
+      tag = hvalue(o)->htag;
+      break;
+    default:
+      tag = t;
+  }
+  ts = G->TMtable[tag].name;
+  if (ts == NULL)
+    ts = G->TMtable[t].name;
+  return ts->str;
+}
+
+
 LUA_API void lua_gettagmethod (lua_State *L, int t, const char *event) {
   int e;
   LUA_ENTRY;
@@ -152,7 +176,7 @@ LUA_API void lua_settagmethod (lua_State *L, int t, const char *event) {
   checktag(L, t);
   if (!luaT_validevent(t, e))
     luaO_verror(L, "cannot change `%.20s' tag method for type `%.20s'%.20s",
-                luaT_eventname[e], luaO_typenames[t],
+                luaT_eventname[e], basictypename(G(L), t),
                 (t == LUA_TTABLE || t == LUA_TUSERDATA) ?
                    " with default tag" : "");
   switch (ttype(L->top - 1)) {

+ 8 - 2
ltm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.h,v 1.20 2001/01/19 13:20:30 roberto Exp roberto $
+** $Id: ltm.h,v 1.21 2001/01/24 16:20:54 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -38,6 +38,7 @@ typedef enum {
 
 /*
 ** masks for allowable tag methods
+** (see `luaT_validevents')
 */
 #define HAS_TM_GETGLOBAL(L,t)	(1<<(t) & ((1<<LUA_TUSERDATA) | \
                                            (1<<LUA_TTABLE) | \
@@ -53,12 +54,16 @@ typedef enum {
 struct TM {
   Closure *method[TM_N];
   TString *collected;  /* list of garbage-collected udata with this tag */
+  TString *name;  /* type name */
+  int basictype;
 };
 
 
 #define luaT_gettm(G,tag,event) (G->TMtable[tag].method[event])
 #define luaT_gettmbyObj(G,o,e)  (luaT_gettm((G),luaT_tag(o),(e)))
 
+#define basictypename(G, t)	(G->TMtable[t].name->str)
+
 
 #define validtag(G,t) (NUM_TAGS <= (t) && (t) < G->ntag)
 
@@ -66,7 +71,8 @@ extern const char *const luaT_eventname[];
 
 
 void luaT_init (lua_State *L);
-void luaT_realtag (lua_State *L, int tag);
+int luaT_newtag (lua_State *L, const char *name, int basictype);
+const char *luaT_typename (global_State *G, const TObject *o);
 int luaT_tag (const TObject *o);
 int luaT_validevent (int t, int e);  /* used by compatibility module */
 

+ 8 - 2
lua.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.h,v 1.82 2001/01/10 16:58:11 roberto Exp roberto $
+** $Id: lua.h,v 1.83 2001/01/22 18:01:38 roberto Exp roberto $
 ** Lua - An Extensible Extension Language
 ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil
 ** e-mail: [email protected]
@@ -102,6 +102,7 @@ LUA_API int   lua_stackspace (lua_State *L);
 
 LUA_API int            lua_type (lua_State *L, int index);
 LUA_API const char    *lua_typename (lua_State *L, int t);
+LUA_API const char    *lua_xtype (lua_State *L, int index);
 LUA_API int            lua_isnumber (lua_State *L, int index);
 LUA_API int            lua_isstring (lua_State *L, int index);
 LUA_API int            lua_iscfunction (lua_State *L, int index);
@@ -173,7 +174,8 @@ LUA_API void  lua_setgcthreshold (lua_State *L, int newthreshold);
 /*
 ** miscellaneous functions
 */
-LUA_API int   lua_newtag (lua_State *L);
+LUA_API int   lua_newtype (lua_State *L, const char *name, int basictype);
+LUA_API int   lua_type2tag (lua_State *L, const char *name);
 LUA_API int   lua_copytagmethods (lua_State *L, int tagto, int tagfrom);
 LUA_API void  lua_settag (lua_State *L, int tag);
 
@@ -212,6 +214,10 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size);
 
 #define lua_pushliteral(L, s)	lua_pushlstring(L, "" s, (sizeof(s))-1)
 
+
+
+#define lua_newtag(L)	lua_newtype(L, NULL, LUA_TNONE)
+
 #endif