Lua debugger: much better Lua values pretty printer.

This commit is contained in:
antirez 2015-11-11 19:46:55 +01:00
parent f4805800dc
commit 1f8fdafe65
2 changed files with 70 additions and 17 deletions

View File

@ -525,7 +525,7 @@ sds sdsCatColorizedLdbReply(sds o, char *s, size_t len) {
if (strstr(s,"<redis>")) color = "green";
if (strstr(s,"<reply>")) color = "cyan";
if (strstr(s,"<error>")) color = "red";
if (strstr(s,"<value>")) color = "magenta";
if (strstr(s,"<value>") || strstr(s,"<retval>")) color = "magenta";
if (len > 4 && isdigit(s[3])) {
if (s[1] == '>') color = "yellow"; /* Current line. */
else if (s[2] == '#') color = "bold"; /* Break point. */

View File

@ -1728,48 +1728,99 @@ void ldbList(int around, int context) {
}
}
/* Produce a debugger log entry representing the value of the Lua object
* currently on the top of the stack. As a side effect the element is
* popped. */
void ldbLogStackValue(lua_State *lua, char *prefix) {
int t = lua_type(lua,-1);
sds s = sdsnew(prefix);
/* Append an human readable representation of the Lua value at position 'idx'
* on the stack of the 'lua' state, to the SDS string passed as argument.
* The new SDS string with the represented value attached is returned.
* Used in order to implement ldbLogStackValue().
*
* The element is not automatically removed from the stack, nor it is
* converted to a different type. */
sds ldbCatStackValue(sds s, lua_State *lua, int idx) {
int t = lua_type(lua,idx);
switch(t) {
case LUA_TSTRING:
s = sdscat(s,lua_tostring(lua,-1));
{
size_t strl;
char *strp = (char*)lua_tolstring(lua,idx,&strl);
s = sdscatrepr(s,strp,strl);
}
break;
case LUA_TBOOLEAN:
s = sdscat(s,lua_toboolean(lua,-1) ? "true" : "false");
s = sdscat(s,lua_toboolean(lua,idx) ? "true" : "false");
break;
case LUA_TNUMBER:
s = sdscatprintf(s,"%g",(double)lua_tonumber(lua,-1));
s = sdscatprintf(s,"%g",(double)lua_tonumber(lua,idx));
break;
case LUA_TNIL:
s = sdscat(s,"nil");
s = sdscatlen(s,"nil",3);
break;
case LUA_TTABLE:
{
int expected_index = 1; /* First index we expect in an array. */
int is_array = 1; /* Will be set to null if check fails. */
/* Note: we create two representations at the same time, one
* assuming the table is an array, one assuming it is not. At the
* end we know what is true and select the right one. */
sds repr1 = sdsempty();
sds repr2 = sdsempty();
lua_pushnil(lua); /* The first key to start the iteration is nil. */
while (lua_next(lua,idx-1)) {
/* Test if so far the table looks like an array. */
if (is_array &&
(lua_type(lua,-2) != LUA_TNUMBER ||
lua_tonumber(lua,-2) != expected_index)) is_array = 0;
/* Stack now: table, key, value */
/* Array repr. */
repr1 = ldbCatStackValue(repr1,lua,-1);
repr1 = sdscatlen(repr1,"; ",2);
/* Full repr. */
repr2 = ldbCatStackValue(repr2,lua,-2);
repr2 = sdscatlen(repr2,"=",1);
repr2 = ldbCatStackValue(repr2,lua,-1);
repr2 = sdscatlen(repr2,"; ",2);
lua_pop(lua,1); /* Stack: table, key. Ready for next iteration. */
expected_index++;
}
/* Strip the last " ;" from both the representations. */
if (sdslen(repr1)) sdsrange(repr1,0,-3);
if (sdslen(repr2)) sdsrange(repr2,0,-3);
/* Select the right one and discard the other. */
s = sdscatlen(s,"{",1);
s = sdscatsds(s,is_array ? repr1 : repr2);
s = sdscatlen(s,"}",1);
sdsfree(repr1);
sdsfree(repr2);
}
break;
case LUA_TFUNCTION:
case LUA_TUSERDATA:
case LUA_TTHREAD:
case LUA_TLIGHTUSERDATA:
{
const void *p = lua_topointer(lua,-1);
const void *p = lua_topointer(lua,idx);
char *typename = "unknown";
if (t == LUA_TTABLE) typename = "table";
else if (t == LUA_TFUNCTION) typename = "function";
if (t == LUA_TFUNCTION) typename = "function";
else if (t == LUA_TUSERDATA) typename = "userdata";
else if (t == LUA_TTHREAD) typename = "thread";
else if (t == LUA_TLIGHTUSERDATA) typename = "light-userdata";
s = sdscatprintf(s,"%s at %p",typename,p);
s = sdscatprintf(s,"%s@%p",typename,p);
}
break;
default:
s = sdscat(s,"?");
s = sdscat(s,"<unknown-lua-type>");
break;
}
return s;
}
/* Produce a debugger log entry representing the value of the Lua object
* currently on the top of the stack. The element is ot popped nor modified.
* Check ldbCatStackValue() for the actual implementation. */
void ldbLogStackValue(lua_State *lua, char *prefix) {
sds s = sdsnew(prefix);
s = ldbCatStackValue(s,lua,-1);
ldbLog(s);
lua_pop(lua,1);
}
char *ldbRedisProtocolToHuman_Int(sds *o, char *reply);
@ -1875,6 +1926,7 @@ void ldbPrint(lua_State *lua, char *varname) {
i++;
if (strcmp(varname,name) == 0) {
ldbLogStackValue(lua,"<value> ");
lua_pop(lua,1);
return;
} else {
lua_pop(lua,1); /* Discard the var name on the stack. */
@ -1954,6 +2006,7 @@ void ldbEval(lua_State *lua, sds *argv, int argc) {
return;
}
ldbLogStackValue(lua,"<retval> ");
lua_pop(lua,1);
}
/* Read debugging commands from client. */