lua-users home
lua-l archive

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


Hi,

while working with lua I made numerous modifications to the source.
IMHO, some of them should be in the standard version.

1. Allow the $if/$ifnot statement to test if debugging is turned on
   so that one can add additional debugging code in lua programs.
   Example:

$if $debug
    print("x.n=", getn(x))
    foreach(x, function(i,v) assert(type(i)=="number", "bad x") end)
$end

   Here's a patch that implements this:   

--- llex.c    Thu Jun 17 19:04:03 1999
+++ llex.c    Thu Mar 23 19:32:50 2000
@@ -117,8 +117,9 @@
 
 
 static int checkcond (LexState *LS, char *buff) {
-  static char *opts[] = {"nil", "1", NULL};
+  static char *opts[] = {"nil", "1", "$debug", NULL};
   int i = luaL_findstring(buff, opts);
+  if (i == 2) return L->debug;
   if (i >= 0) return i;
   else if (isalpha((unsigned char)buff[0]) || buff[0] == '_')
     return luaS_globaldefined(buff);
@@ -132,7 +133,7 @@
 static void readname (LexState *LS, char *buff) {
   int i = 0;
   skipspace(LS);
-  while (isalnum(LS->current) || LS->current == '_') {
+  while (isalnum(LS->current) || LS->current == '_' || LS->current == '$') {
     if (i >= PRAGMASIZE) {
       buff[PRAGMASIZE] = 0;
       luaX_syntaxerror(LS, "pragma too long", buff);



2. The second argument to the next() function should be optional so that
   next(foo, nil) is the same as next(foo).  I use next() regularly to test
   if a table is empty (if next(tab) then print"not empty" end) and the 
   additional nil is disturbing and inconsistent.

--- lbuiltin.c  Sun Apr  2 19:15:41 2000
+++ lbuiltin.c  Sun Apr  2 19:51:54 2000
@@ -320,15 +320,15 @@
 
 static void luaB_next (void) {
   Hash *a = gethash(1);
-  TObject *k = luaA_Address(luaL_nonnullarg(2));
-  int i = (ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1;
+  TObject *k = luaA_Address(lua_getparam(2));
+  int i = (k == 0 || ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1;
   if (luaA_next(a, i) == 0)
     lua_pushnil();
 }

[Side note]
   In my opinion there's an unnecessary difference between handling
   of arguments to C functions and lua functions.  A lua function
   f(a,b) cannot say if it was called via f(a,nil) or f(a).  A C
   function gets either a nil or LUA_NOOBJECT for b.  Why this
   difference?  Isn't nil supposed to stand for "no object"?  ;-)

   I think it would have been better to return nil for not passed
   arguments.  The functions that check for optional arguments
   check against nil instead of LUA_NOOBJECT (then giving exactly the
   same behavior as lua functions).  And an additional function (i.e
   lua_narg()) gives the real number of passed arguments to simulate
   vararg lua functions.

   But I guess it's too late now...



3. The last thing is a little bit more difficult.  A garbage collected
   system is a nice thing to have.  You don't have to care about freeing
   objects.  But often you come to the situation that you want to create
   a new one and assume that it is already present somewhere.  For example,
   you have a function to load a graphics image.  It gets a file name,
   load's it and returns an image object.  The object itself is garbage
   collected.  Now, you want to cache all images, so that you don't have
   to load the same image multiple times.  But unfortunately, the cache
   itself holds a reference to every image and it is no longer garbage
   collected :-(

   What you want: weak references that won't hinder the gc of collecting
   the referenced object.

   My first idea was:  add a function to mark a table as holding weak
   reference which means, all values (not indexes) hold in that table
   will not be marked during the mark phase.  Later in the collection
   phase replace all table values not marked with nil.  But the imple-
   mentation is not that easy and I'm still not sure if this really
   works.  (I would love to hear comments about this idea, especially
   if this would really work.)

   So I went an easier way.  The C-API already has a method to hold weak
   references (lua_ref(0)).  I just created some bindings to access them
   from lua.  Because the references itself have to be garbage collected
   I mapped them to userdata with a private tag.  The result:  there are
   two new functions, x = ref(obj) and  obj = getref(x).  getref returns
   nil if the object referenced by x is already garbage collected.

   I think, these two function are elementary enough to be part of the
   standard list of builtin functions (the short names may be a problem).

   Here is a code fragment of my implementation:

lua_api
xlua_ref(void)
{
    lua_pushobject(luaL_nonnullarg(1));
    lua_pushusertag((void*)lua_ref(0), tag_ref);
}

lua_api
xlua_getref(void)
{
    lua_Object o = lua_getparam(1);

    luaL_arg_check(lua_tag(o) == tag_ref, 1, "reference expected");
    o = lua_getref((int)lua_getuserdata(o));
    if (o != LUA_NOOBJECT) /* object not already gc'ed */
        lua_pushobject(o);
}

static void
gc_ref(void)
{
    lua_unref((int)lua_getuserdata(lua_getparam(1)));
}



Ok, that's all for the moment.  Discussion opened *g*

Ciao, ET.