Reputation: 923
I have an application that periodically will run a Lua script. Within the script, on occasion, I have created a custom registered Lua function to check some parameters and decide if the Lua script should continue or exit. The logic ideally should not be part of the script and I can think of using a Lua script to work around this, but I'm wondering if it is possible to stop the execution of a Lua script without ending the application.
I have a custom function written in Delphi and exposed to Lua scripts using Lua 5.1. The Lua script looks something like that shown below and the script in Lua is started using luaL_loadbuffer
.
io.write("Script starting\n");
--Custom Function
ExitIfFound();
io.write("Script continuing\n");
My custom function looks something like this, below I have provided one of my attempts where I tried to use lua_error
to stop the script...
function ExitIfFound(LuaState: TLuaState): Integer;
var
s: AnsiString;
begin
s := 'ExitIfFound ending script, next Lua script line not called';
lua_pushstring(LuaState, PAnsiString(s));
lua_error(LuaState);
end;
When my custom function is called, I'm unsure as to how to exit the Lua script without any further evaluation. I have seen posts referring to Lua and using setjmp
and longjmp
in C, but I'm curious how these may translate Delphi.
In the example above, when I use lua_error
, the entire program crashes with Windows doing its typical, [luarun.exe has stopped working]
...
With all of this, I'm am still pretty new to integrating Lua to Delphi and hoping that I can find some cleaner options to explore.
Upvotes: 3
Views: 909
Reputation: 163287
There is no clean way to entirely abort a Lua script. The lua_error
function is the correct way to signal an error. It is the caller's responsibility to catch the error and propagate it to the next caller.
If you cannot rely on the caller to cooperate, then you can try to exert more control by installing debug hooks. Then the host program will be consulted before continuing to run the script. However, the script can still avoid exiting by using pcall
to catch any errors.
The crash in your program is probably not simply from setting an error. Rather, it's likely from using the wrong calling convention on your ExitIfFound
function. It needs to be cdecl, but Delphi's default, if you don't specify anything else, is register. Using the wrong calling convention will give you unpredictable parameter values and can lead to a corrupted stack. If you type-casted the function or used the @
operator when you called lua_register
, then you might have hidden the calling-convention mismatch from the compiler's type checker, which would have otherwise alerted you to the problem at compile time.
When compiled as C++, lua_error
will use a exception instead of longjmp
, but either way, the caller always catches the error. Exceptions are important, though, when your Delphi code uses compiler-managed types like string
, or exception-sensitive constructs like try
-finally
blocks. In C mode, lua_error
calls longjmp
to jump directly to the waypoint set by a previous call to setjmp
. That jump will skip over any exception handlers like the ones the Delphi compiler sets up to ensure the finally
block runs and the string gets cleaned up.
A further headache is that since the compiler cleans up the string while exiting the function, the pointer you put on the Lua stack might not be valid by the time it's used; that depends on whether lua_pushstring
makes a copy of its argument.
Upvotes: 1