我有一个定期运行Lua脚本的应用程序。在脚本中,有时,我创建了一个自定义注册的Lua函数来检查一些参数,并决定是否应该继续或退出Lua脚本。理想情况下,逻辑不应该是脚本的一部分,我可以考虑使用Lua脚本来解决这个问题,但我想知道是否可以在不结束应用程序的情况下停止执行Lua脚本。
我有一个用Delphi编写的自定义函数,并使用Lua 5.1暴露给Lua脚本。 Lua脚本看起来如下所示,Lua中的脚本使用luaL_loadbuffer
启动。
io.write("Script starting\n");
--Custom Function
ExitIfFound();
io.write("Script continuing\n");
我的自定义函数看起来像这样,下面我提供了一个尝试使用lua_error
停止脚本的尝试...
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;
当调用我的自定义函数时,我不确定如何在没有任何进一步评估的情况下退出Lua脚本。我看过帖子引用Lua并在C中使用setjmp
和longjmp
,但我很好奇这些文章如何翻译Delphi。
在上面的示例中,当我使用lua_error
时,整个程序崩溃,Windows执行其典型的[luarun.exe has stopped working]
...
有了这一切,我仍然很难将Lua集成到Delphi,并希望我能找到一些更清晰的选择来探索。
答案 0 :(得分:1)
没有干净的方法可以完全中止Lua脚本。 lua_error
函数是发出错误信号的正确方法。调用者有责任捕获错误并将其传播给下一个调用者。
如果您不能依赖调用者进行合作,那么您可以尝试以通过installing debug hooks施加更多控制。然后,在继续运行脚本之前,将咨询主程序。但是,the script can still avoid exiting by using pcall
to catch any errors。
程序中的崩溃可能不仅仅是设置错误。相反,它可能来自您ExitIfFound
函数的错误调用约定。它需要是cdecl,但是Delphi的默认值,如果你没有指定其他东西,就是寄存器。使用错误的调用约定将为您提供不可预测的参数值,并可能导致堆栈损坏。如果您在调用@
时键入了该函数或使用了lua_register
运算符,那么您可能已经隐藏了编译器类型检查器中的调用约定不匹配,否则会提醒您注意该问题在编译时。
当编译为C ++时,lua_error
将使用异常而不是longjmp
,但无论如何,调用者总是捕获错误。但是,当您的Delphi代码使用编译器管理的类型(如string
)或异常敏感的构造(如try
- finally
块时,例外很重要。在C模式下,lua_error
调用longjmp
直接跳转到之前调用setjmp
所设置的航点。该跳转将跳过任何异常处理程序,例如Delphi编译器设置的异常处理程序,以确保finally
块运行并清除字符串。
进一步令人头疼的是,由于编译器在退出函数时清除了字符串,因此放在Lua堆栈上的指针在使用时可能无效;这取决于lua_pushstring
是否复制了其参数。