Open starwing opened 9 years ago
Hello.
Just to understand a little bit more, you mean instead of lua_call
you want to use lua_pcall
and allow you to use a message handler along with it? It sounds plausible but I'm not sure how to add it to the API sanely.
I had wanted to (unrelated to this issue slightly) allow users to set the lua_atpanic
function to disable exceptions so that's on the roadmap sometime in the future too.
I have some ideas, the feature requires are:
The first is simple, just use lua_pcall instead (and maybe add a luaL_traceback wrapper or just retrieve debug.traceback()). But I don't have mind about the second: what result the call() return? maybe a result_or_errmsg
class or some better ones?
I can start on this by setting up a function pointer to be called on lua_atpanic. Since it's coupled to the lua_State, it can be passed into the constructor for sol::state
like or set up using sol::state lua; lua.at_panic( my_function );
. We'll allow for any C++ function that matches the signature, (placed into a std::function).
As a sidenote, I've never worked without exceptions. If you turn them off, what happens when you throw
in code? Does the compiler demand you remove all instances of throw
? Or does it just insert some std::terminate
-like code everywhere a library uses "throw"?
@starwing As a quick question, do you use -fno-exceptions
or is it just your codebase policy to never try/catch
and still have them on? I ask because this (http://stackoverflow.com/questions/7249378/disabling-c-exceptions-how-can-i-make-any-std-throw-immediately-terminate) says its a compile-time error for folks who use -fno-exceptions
, and that'll be a bit harder to work around.
Preliminary support. I do not have the mechanism for having a "error message handler", but I believe I would add functionality to add that kind of trampoline to sol::function
. Right now, there is no message handler but we do use pcall
if you do not automatically convert the return type:
#include "sol.hpp"
#include <iostream>
int main( int argc, char * const argv[] ) {
sol::state lua;
// Some function; just using a lambda to be quick
auto SOULS = []() {
throw std::exception( "dun goofed, little man" );
};
// Set the function
lua.set_function( "doom", SOULS );
sol::function luaSOULS = lua[ "doom" ];
// can also do auto x = ...;
sol::function_result x = luaSOULS();
if ( x.valid() ) {
// call succeeded
std::cout << "Mmm, delicious success";
}
else {
// call failed, USUALLY lua leaves a message string on top or something
// Not always the case if you do something zany with the message handler, but we don't
// have code in `sol` that allows for custom message handlers (yet)
// This will also be the case if a regular std::exception (or derived) is thrown
std::string errorstring = x;
std::cout << "OH GOD SAVE US ALL!\n"
<< "The harbinger said: \"" << errorstring << "\"";
}
}
Note that if you captured lua
or got the lua_State*
somehow, this example would also work if you just used luaL_error
instead of throw std::exception(...)
.
Custom handling seems to work in #62. But, in order to make this work with handlers there's a wee bit of extra overhead (to set the special handler). Should probably use a little extra template magic to eliminate the runtime check for a handler if the user specifies that its a no-fail function.
#include "sol.hpp"
#include <iostream>
int main( int argc, char * const argv[] ) {
sol::state lua;
lua.open_libraries( sol::lib::base, sol::lib::debug );
// Some function; just using a lambda to be cheap
auto doom = []() {
// Bypasses handler function: puts information directly into lua error
throw std::exception( "dun goofed, little man" );
};
auto luadoom = [&lua]() {
// Does not bypass error function, will call it
lua_error( lua.lua_state() );
};
// Set the function
lua.set_function( "doom", doom );
lua.set_function( "luadoom", luadoom );
lua.script(
"function handler ( message )"
" return message .. debug.traceback()"
"end"
);
sol::function func = lua[ "doom" ];
sol::function luafunc = lua[ "luadoom" ];
sol::function luahandler = lua[ "handler" ];
// Make sure handler works
luahandler();
// Set it
// function_result pops the results when its destructor is called
// so scope it appropriately!
// If you don't scope it, runtime will have to remove arguments from middle
// of the stack (which can (???, untested)) be costly
sol::function_result result1 = func();
if ( result1.valid() ) {
// call succeeded
std::cout << "result 1";
// manipulate contents
}
else {
// call failed,
// USUALLY lua leaves a message string on top or something
std::string errorstring = result1;
std::cout << "result1 error:\n" << errorstring << '\n';
}
// Appropriately scoped
luafunc.error_handler = luahandler;
sol::function_result result2 = luafunc();
if ( result2.valid() ) {
// call succeeded
std::cout << "result2 success";
// manipulate contents
}
else {
// call failed,
// USUALLY lua leaves a message string on top or something
std::string errorstring = result2;
std::cout << "result2 error:\n" << errorstring << '\n';
}
}
That's awesome! Sorry for late reply as I'm working hard on Lua scripts for Unity client :(
I will look into this but this is really awesome! Thank you for your really outstanding work!
Hi, I found this library do not use lua_pcall. I prefer to call a lua function with a message handler to offer a stack trace in error. so a function like lua.where() and lua.error([msg before where]) is good. have some plans to support this?