Lua: print() can print any type, add tostringx() for print-to-string

This commit is contained in:
Ilari Liusvaara 2013-09-27 04:15:01 +03:00
parent 837aa6def0
commit ba1d20dda5
5 changed files with 138 additions and 32 deletions

View file

@ -5,6 +5,8 @@
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <list>
#include <functional>
extern "C"
{
#include <lua.h>
@ -19,6 +21,9 @@ extern bool lua_booted_flag;
extern uint64_t lua_idle_hook_time;
extern uint64_t lua_timer_hook_time;
std::list<std::string(*)(lua_State* LS, int index)>& userdata_recogn_fns();
std::string try_recognize_userdata(lua_State* LS, int index);
template<typename T>
T get_numeric_argument(lua_State* LS, unsigned argindex, const char* fname)
{
@ -90,6 +95,7 @@ public:
lua_class(const std::string& _name)
{
name = _name;
userdata_recogn_fns().push_back(lua_class<T>::recognize);
}
template<typename... U> T* _create(lua_State* LS, U... args)
@ -208,6 +214,16 @@ badtype:
return objclass<T>()._is(LS, arg);
}
std::string _recognize(lua_State* LS, int arg)
{
return _is(LS, arg) ? name : "";
}
static std::string recognize(lua_State* LS, int arg)
{
return objclass<T>()._recognize(LS, arg);
}
lua_obj_pin<T>* _pin(lua_State* LS, int arg, const char* fname)
{
T* obj = get(LS, arg, fname);

View file

@ -1923,6 +1923,15 @@ print
Print line to message console.
\end_layout
\begin_layout Subsubsection
tostringx
\end_layout
\begin_layout Standard
Convert arbitrary lua value into a string (using same conversions as print)
and return the result.
\end_layout
\begin_layout Subsubsection
exec(string command)
\end_layout

View file

@ -940,36 +940,41 @@ Sets the delay for subsequent characters in typematic autorepeat.
Print line to message console.
8.1.2 exec(string command)
8.1.2 tostringx
Convert arbitrary lua value into a string (using same conversions
as print) and return the result.
8.1.3 exec(string command)
Run command as it was entered on the command line
8.1.3 utime()
8.1.4 utime()
Returns two values. First is time since some epoch in seconds,
the second is microseconds mod 10^6 since that epoch.
8.1.4 emulator_ready()
8.1.5 emulator_ready()
Returns true if emulator has finished booting, false if not
(on_startup() will be issued later).
8.1.5 set_idle_timeout(number timeout)
8.1.6 set_idle_timeout(number timeout)
Set number of microseconds to block idle for. After this timeout
has expired, on_idle() will be called once.
8.1.6 set_timer_timeout(number timeout)
8.1.7 set_timer_timeout(number timeout)
Set number of microseconds to block timer for. After this timeout
has expired, on_timer() will be called once.
8.1.7 bus_address(number snesaddr)
8.1.8 bus_address(number snesaddr)
Returns virtual address corresponding to specified address on
SNES bus.
8.1.8 loopwrapper(function fun, ...)
8.1.9 loopwrapper(function fun, ...)
Calls function fun with function and specified arguments. The
function passed suspends execution until the function returned is
@ -988,21 +993,21 @@ on_paint = loopwrapper(function(wait)
end);
8.1.9 list_bindings([string cmd])
8.1.10 list_bindings([string cmd])
Get table of all keybindings, indexed by keyspec
(modifiers|mask/key). If command is specified, the table is
limited to that command.
8.1.10 get_alias(string aname)
8.1.11 get_alias(string aname)
Get expansion of given alias.
8.1.11 set_alias(string aname, string value)
8.1.12 set_alias(string aname, string value)
Set expansion of given alias.
8.1.12 create_ibind(string name, string cmd)
8.1.13 create_ibind(string name, string cmd)
Return object representing inverse binding with specified name
and specified command.

View file

@ -3,9 +3,75 @@
#include "lua/internal.hpp"
#include "core/framerate.hpp"
#include "core/window.hpp"
#include "library/string.hpp"
#include <sstream>
namespace
{
std::string luavalue_to_string(lua_State* LS, int index, std::set<const void*>& printed, bool quote)
{
switch(lua_type(LS, index)) {
case LUA_TNONE:
return "none";
case LUA_TNIL:
return "nil";
case LUA_TBOOLEAN:
return lua_toboolean(LS, index) ? "true" : "false";
case LUA_TNUMBER:
return (stringfmt() << lua_tonumber(LS, index)).str();
case LUA_TSTRING: {
const char* tmp2;
size_t len;
tmp2 = lua_tolstring(LS, index, &len);
if(quote)
return "\"" + std::string(tmp2, tmp2 + len) + "\"";
else
return std::string(tmp2, tmp2 + len);
}
case LUA_TLIGHTUSERDATA:
return (stringfmt() << "Lightuserdata:" << lua_touserdata(LS, index)).str();
case LUA_TFUNCTION:
return (stringfmt() << "Function:" << lua_topointer(LS, index)).str();
case LUA_TTHREAD:
return (stringfmt() << "Thread:" << lua_topointer(LS, index)).str();
break;
case LUA_TUSERDATA:
return (stringfmt() << "Userdata<" << try_recognize_userdata(LS, index) << ">:"
<< lua_touserdata(LS, index)).str();
case LUA_TTABLE: {
//Fun with recursion.
const void* ptr = lua_topointer(LS, index);
if(printed.count(ptr))
return (stringfmt() << "<table:" << ptr << ">").str();
printed.insert(ptr);
std::ostringstream s;
s << "<" << ptr << ">{";
lua_pushnil(LS);
bool first = true;
while(lua_next(LS, index)) {
if(!first)
s << ", ";
int stacktop = lua_gettop(LS);
s << "[" << luavalue_to_string(LS, stacktop - 1, printed, true) << "]="
<< luavalue_to_string(LS, stacktop, printed, true);
first = false;
lua_pop(LS, 1);
}
s << "}";
return s.str();
}
default:
return (stringfmt() << "???:" << lua_topointer(LS, index)).str();
}
}
function_ptr_luafun lua_tostringx("tostringx", [](lua_State* LS, const std::string& fname) -> int {
std::set<const void*> tmp2;
std::string y = luavalue_to_string(LS, 1, tmp2, false);
lua_pushlstring(LS, y.c_str(), y.length());
return 1;
});
function_ptr_luafun lua_print("print", [](lua_State* LS, const std::string& fname) -> int {
int stacksize = 0;
while(!lua_isnone(LS, stacksize + 1))
@ -13,29 +79,12 @@ namespace
std::string toprint;
bool first = true;
for(int i = 0; i < stacksize; i++) {
size_t len;
const char* tmp = NULL;
if(lua_isnil(LS, i + 1)) {
tmp = "nil";
len = 3;
} else if(lua_isboolean(LS, i + 1) && lua_toboolean(LS, i + 1)) {
tmp = "true";
len = 4;
} else if(lua_isboolean(LS, i + 1) && !lua_toboolean(LS, i + 1)) {
tmp = "false";
len = 5;
} else {
tmp = lua_tolstring(LS, i + 1, &len);
if(!tmp) {
tmp = "(unprintable)";
len = 13;
}
}
std::string localmsg(tmp, tmp + len);
std::set<const void*> tmp2;
std::string tmp = luavalue_to_string(LS, i + 1, tmp2, false);
if(first)
toprint = localmsg;
toprint = tmp;
else
toprint = toprint + "\t" + localmsg;
toprint = toprint + "\t" + tmp;
first = false;
}
platform::message(toprint);

View file

@ -670,6 +670,33 @@ bool lua_do_once(lua_State* LS, void* key)
}
}
std::list<std::string(*)(lua_State* LS, int index)>& userdata_recogn_fns()
{
static std::list<std::string(*)(lua_State* LS, int index)> x;
return x;
}
std::string try_recognize_userdata(lua_State* LS, int index)
{
for(auto i : userdata_recogn_fns()) {
std::string x = i(LS, index);
if(x != "")
return x;
}
//Hack: Lua builtin file objects.
lua_pushstring(LS, "FILE*");
lua_rawget(LS, LUA_REGISTRYINDEX);
if(lua_getmetatable(LS, index)) {
if(lua_rawequal(LS, -1, -2)) {
lua_pop(LS, 2);
return "FILE*";
}
lua_pop(LS, 1);
}
lua_pop(LS, 1);
return "unknown";
}
bool lua_requests_repaint = false;
bool lua_requests_subframe_paint = false;
bool lua_supported = true;