Lua: print() can print any type, add tostringx() for print-to-string
This commit is contained in:
parent
837aa6def0
commit
ba1d20dda5
5 changed files with 138 additions and 32 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
27
manual.txt
27
manual.txt
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue