lua-users home
lua-l archive

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


[sorry, weekends often interrupt my train of thought]

On 6 Oct 2006, at 18:10, Glenn Maynard wrote:

On Fri, Oct 06, 2006 at 11:39:32AM +0100, David Jones wrote:
What mystic forces locates "code snippets" can arrange that when a
located code snippet wants to "source in" another chunk the mystic
invocation that it uses to do that "source in" the other code chunk
is able to find the code chunk using the information that was
obtained when the first code snippet was located.

I'm not sure what information you're referring to.  If I load a chunk:

return { a = "file", parts = { loadfile("tail.lua"), loadfile ("nose.lua") } };

with luaL_loadfile(L, "asset/path/dog/dog.lua", and evaluate it later
on, I can't see any way at that point to discover "asset/path/dog/",
other than by parsing it out of debug info.

Right, I see what you're trying to do now, I think.

If everything's done in Lua then you can do it by a horrible hack which I'll try and describe.

Assume whenever Lua script A loads Lua script B it uses loadfile'...blah...B', and that loadfile is the only way to load scripts.

Clearly if A knows where it is then loadfile can know where A is, find B relative to that, and make that information available to B. The trick is that we're not executing B now, we're executing it later. So the idea is...

A and B have different versions of "loadfile", this is made possible by metatabling the environment of loaded chunks so that they each get a different version of the "global" loadfile.

Broadly, loadfile is changed so that:
- it loads the chunk;
- it computes somehow the location of the loaded chunk (string processing on its full name probably); - it modifieds the environment of the loaded chunk to be a table t such that t.loadfile is a private closure, but otherwise t shadows the globals, so that t[x] is _G[x]; - t.loadfile has available to it the location of the loaded chunk, so when the loaded chunk executes and calls loadfile that loadfile can use the location of the loaded chunk to locate the requested chunk.

This seems like a lot of hassle merely to avoid using the debug API.


I suppose I could also store the path in a weak table, keyed to the
chunk itself.  That wouldn't need any special attention if debug
information was disabled for low-memory systems.

This almost works but in general a chunk can't get a reference to itself. You either have to explicitly pass the chunk to itself every time you called it, or modify the chunk's environment so that the chunk was always available at some well known free variable. Or use the debug API to get the executing chunk, but then that doesn't avoid the debug API.

You presumably have some function "foo" that finds another code chunk
and runs it?  "foo" can arrange that when it is running another code
chunk and that code chunk does "foo" its "foo" is able to find code
chunk relative to the first one.  "foo" knows this because it found
the first code chunk in the first place.

I have no "foo"; that's exactly what I'm planning to implement.
Currently, I only load individual code chunks, with absolute paths.

Another issue I'm thinking of with this scheme: there's no way to tell
what bit of code created any part of the table. That makes useful error
messages impossible, once the recursive loading becomes non-trivial.
Right now each part is loaded on-demand, so the path is still available
when it's used, but I'd really like loading to be done natively.  Hmm.

You could impose a convention that no chunk was allowed to create tables except via a special, newtable, function. But that sucks. Apart from that there's no way to tell from a table who created it. Which makes me think that...

Wouldn't it be nice if the creation of tables (and possibly other allocated objects like userdata and functions) was somehow hookable or metatableised? Then you could arrange that every table created by module foo was branded as being created by foo.

drj