[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Some enhancement requests
- From: Edgar Toernig <froese@...>
- Date: Sun, 02 Apr 2000 23:10:33 +0200
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.