Joshua Behrens - Tricks und Kniffe für Lua und C++

Tricks und Kniffe für Lua und C++

(letztes Update: 03.05.2013)


Ich habe wieder viel mit Lua gearbeitet und kam auf einige Probleme. Um Lösungen für einige Probleme für andere und mich festzuhalten, habe ich meine Lösungen hier aufgelistet. Generell sollte festgehalten werden, dass ich um einfach Bindings zu erstellen LuaBridge nutze und nur weiterempfehlen kann.
Wenn man mit direkten CFunctions arbeitet ist es immer sinnvoll den Stack im Auge zu behalten. Dazu ist es immer gut den Stack festzuhalten. Egal ob in der Konsole oder in einer Datei, dank std::ostream schön variabel.
inline void PrintLuaStack( std::ostream& out_, lua_State* lua_ ) { int index = 0; while ( true ) { out_ << '(' << ++index << ") "; switch ( lua_type( lua_, index ) ) { case LUA_TNUMBER: if ( LUA_NUMBER( lua_tointeger( lua_, index ) ) == lua_tonumber( lua_, index ) ) out_ << "(int) " << lua_tointeger( lua_, index ); else out_ << "(double) " << lua_tonumber( lua_, index ); break; case LUA_TBOOLEAN: out_ << "(bool) " << ( lua_toboolean( lua_, index ) > 0 ? "true" : "false" ); break; case LUA_TSTRING: out_ << "(string) " << lua_tostring( lua_, index ); break; default: out_ << lua_typename( lua_, lua_type( lua_, index ) ); break; } out_ << '\n'; if ( lua_gettop( lua_ ) <= index ) { out_ << "---\n"; break; } } }
Das ist natürlich sehr einfach gehalten und behandelt keine Tables. Für eine komplette Ausgabe des Stacks nutze ich folgende Funktion und folgenden Aufruf:
inline std::string LuaStackAtIndexToString( lua_State* lua_, const int& index_, const int& depth_, const bool& hasprefix_ ) { std::ostringstream oss( "" ); std::string prefix; for ( std::size_t i( 0 ) ; i < depth_ * 4 ; ++i ) prefix += " "; if ( hasprefix_ ) oss << prefix; oss << lua_typename( lua_, lua_type( lua_, index_ ) ) << " "; switch ( lua_type( lua_, index_ ) ) { case LUA_TNUMBER: if ( LUA_NUMBER( lua_tointeger( lua_, index_ ) ) == lua_tonumber( lua_, index_ ) ) oss << lua_tointeger( lua_, index_ ); else oss << lua_tonumber( lua_, index_ ); break; case LUA_TBOOLEAN: oss << ( lua_toboolean( lua_, index_ ) > 0 ? "true" : "false" ); break; case LUA_TSTRING: oss << std::string( lua_tostring( lua_, index_ ) ); break; case LUA_TTABLE: { std::list< std::string > lines; oss << "{\n"; lua_pushnil( lua_ ); int tableindex( depth_ > 0 ? -2 : index_ ); while ( lua_next( lua_, tableindex ) != 0 ) { lines.push_back( LuaStackAtIndexToString( lua_, -2, depth_ + 1, true ) + " = " + LuaStackAtIndexToString( lua_, -1, depth_ + 1, false ) ); lua_pop( lua_, 1 ); } while ( lines.size( ) > 0 ) { oss << *lines.begin( ) << "\n" ; lines.pop_front( ); } oss << prefix << "}"; } break; default: break; } return oss.str( ); } for ( int index( 1 ) ; lua_gettop( lua_ ) >= index ; ++index ) std::cout << LuaStackAtIndexToString( lua_, index, 0, "" ) << "\n";
Um ein normal indiziertes Array aus einer CFunction zurückzugeben kann man ganz einfach Werte auf den Stack pushen und im Skript den Table-Konstruktor nehmen um aus den gestackten Werten ein Array zu bilden:
int _lua_list( lua_State* lua_ ) { if ( lua_gettop( lua_ ) > 0 ) { int x = luabridge::Stack< int >::get( lua_, 1 ); for ( int c( 0 ) ; c < x ; ++c ) luabridge::Stack< int >::push( lua_, c * 2 ); return x; } return 0; }
Und so sähe dann ein Aufruf in Lua aus.
list = { MakeListByCPP( 10 ) }
Sollte man ohne Umweg eine Table ausgeben wollen wurde schon eine gute Möglichkeit auf StackOverflow gepostet.