lua-users home
lua-l archive

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


> I too should like such thing. I think, this can be like following.
> Lua parser has 2 tables: _Modules (key - string: module name;
> value - lightuserdata: pointer to structure luaL_def)
> and _Defs (key - string: from, value - string: to).

I think this could be accomplished in a slightly simpler fashion, 
without major modifications to Lua.

If we are simply dealing with simple constants (integers, say),
then they can be introduced into a Lua script by prefixing the script
with a set of local declarations.

Eg:

local OPEN = 1
local CLOSE = 2
-- remainder of script

Similarly, these can be introduced into a C program by prefacing
an enum declaration:

enum constants {
  OPEN = 1,
  CLOSE = 2
}

The Lua solution will work with more complex objects as well, even
functions and tables, but enums are limited to integers. In any event,
the similarity between the above constructs suggests that a simple
preprocessor could be used to generate the two cases; for example,
the C preprocessor.

Suppose I have a file with the definitions in Lua format:

constants.inc:

  local OPEN = 1
  local CLOSE = 2

Obviously, I can just prepend that file to the Lua script being defined;
that could be easily done by using a custom chunkreader.

To incorporate these into C, I need a bit of trickery:

#include <defconsts.h>
#include "constants.inc"
#include <endconsts.h>

-------File defconsts.h:
#define local ,
enum constants {ZERO
-------

-------File endconsts.h:
#undef local
}
-------

As an alternative to prepending the local definitions, the C preprocessor
could simply be used to preprocess the Lua script; but caution must be
taken to ensure that #line directives do not show up in the output;
This can be done with gnu cpp by supplying the -P flag. Other options
might also be useful, such as not defining standard macros.

I'm assuming here that the scripts are being loaded in LTN 11 style,
so that the script creates a package-table generator which it returns.

Alternatively, the script might simply define an executable which is
executed repeatedly; rather than execute all the local definitions
on each execution of the script function, it is probably reasonable
for the script to return a function with the locals already bound as
upvalues. This can be accomplished using the CPP solution outlined
above, assuming gnu cpp invoked as follows: cpp -D__LUA__ -undef -P

-------File defconsts.h:
#ifndef __LUA__
#  define local ,
enum constants {ZERO
#endif
-------

-------File endconsts.h:
#ifdef __LUA__
return function()
#else
#  undef local
}
#endif
-------

-------File endlua.h
end
-------

Or you could easily produce LTN-11 compatible files:

-------File endconsts.h:
#ifdef __LUA__
return function(PUBLIC)
#  define export function PUBLIC.
#else
#  undef local
}
#endif
-------

------File endlua.h:
  return PUBLIC
end
______

I personally prefer to define member functions just once, rather
than generate new closures for every LTN-11 table:

-------File endconsts.h:
#ifdef __LUA__
#  define export(fn) PUBLIC.fn = fn
#  define pif        return function(PUBLIC)
#  define endpif       return PUBLIC end
#else
#  undef local
}
#endif

So my Lua module would look something like this:

#include <defconsts.h>
#include "constants.inc"
#include <endconsts.h>
local function foo(x) ... end
local function internal(y) ... end
local function debug(x) ... end

pif
  export(foo)
#ifdef __DEBUG__
  export(debug)
#endif
endpif

------------------------------------------

Now, it may be that there are lots of constants in constants.inc, only a 
few
of which are used in each Lua script. This will not affect the generated 
code,
because only upvalues which are actually used will be retained, but it 
will
affect the speed of compiling the script in the first place. I doubt 
whether
this is significant enough to make it worthwhile eliminating constants, 
but
it is easy enough to see how to do that -- unfortunately, cpp is not 
powerful
enough and some other macro processor would be necessary.

Hope this helps someone.
None of the code above has been tested, but I think it would work :)

Rici