|
I am working on embedding Lua as a means of doing policy
control in an email filtering application. I have it working quite nicely
(it was not as hard as I expected!), but I would like to improve one aspect of
its operation. Ideally I’d like the filter to read the Lua
script(s) it’s configured to use and attempt to validate the syntax of
the script as much as possible before the filter is allowed to fork and begin
operating; sort of a “dry run”. This would be akin to “sh
–x” or “perl –c”, or compilation of a C program
before actually running it. I export a few C global variables and a number of C functions
to the scripts, and then use lua_load() to load them and check for
errors. However, I observed that if I insert a typo into one of the
exported function names, lua_load() doesn’t return an error even though
that’s now an unrecognized symbol. For example, if I export a
function “foo” that takes a user data (pointer) and a string as
arguments, and then test this script: -- test script; “ctx” is a global context
pointer exported from C io.write(xfoo(ctx, “hi there”), “\n”) …lua_load() doesn’t complain at all. Only
if I use lua_pcall() will I get some kind of error report out. That
correctly notes that “xfoo” is actually “nil”.
But now if I change it back to “foo”, i.e. it’s correctly
spelled, lua_pcall() will of course actually try to run the script which could
have side effects I don’t want when simply testing the script for syntax
errors. To try to reach some middle ground, I’ve coded the C
side of “foo” so that if it gets a NULL value as “ctx”
it will push some dummy value and return 1 immediately, so there are no side
effects. Since “foo” uses the lua_gettop() and lua_is*()
functions to check that the stack is the right size and contains the right
kinds of arguments, this works to validate that the functions are being called
correctly inside the Lua script. But then I have to make sure that the
dummy value(s) returned in test mode by one function are valid as possible input
to other functions; e.g. if the output of “foo” might be used as
the input to “bar” and “bar” expects strings, then “foo”
can only output a string, and I have to think of all possible combinations of
these. Is there some common wisdom out there for how to go about doing
this sort of work? Am I on the right track? |