wxString wxLuaCheckStack::DumpStack(const wxString& msg) { wxCHECK_MSG(m_luaState, wxEmptyString, wxT("Invalid lua_State")); lua_State* L = m_luaState; int i, count = lua_gettop(L); wxString str; wxString retStr; str.Printf(wxT("wxLuaCheckStack::DumpStack(L=%p), '%s':'%s', items %d, starting top %d\n"), L, m_msg.c_str(), msg.c_str(), count, m_top); retStr += str; OutputMsg(str); wxLuaState wxlState(L); for (i = 1; i <= count; i++) { int wxl_type = 0; wxString value; int l_type = wxLuaDebugData::GetTypeValue(L, i, &wxl_type, value); str.Printf(wxT(" idx %d: l_type = %d, wxl_type = %d : '%s'='%s'\n"), i, l_type, wxl_type, wxluaT_typename(L, wxl_type).c_str(), value.c_str()); retStr += str; OutputMsg(str); } return retStr; }
// %override wxLua_function_typename // %function wxString typename(int wxluaarg_tag) static int LUACALL wxLua_function_typename(lua_State *L) { // int wxluaarg_tag int wxl_type = (int)wxlua_getnumbertype(L, 1); // call wxlua_getwxluatypename wxString returns = wxluaT_typename(L, wxl_type); // push the result string wxlua_pushwxString(L, returns); return 1; }
wxString wxLuaDebugData::GetUserDataInfo(lua_State *L, int stack_idx, bool full_userdata) { wxCHECK_MSG(L, wxEmptyString, wxT("Invalid lua_State")); void* udata = lua_touserdata(L, stack_idx); wxString s(wxString::Format(wxT("%p"), udata)); if (!full_userdata) { // Convert our known keys to something more readable if ((udata == &wxlua_lreg_types_key) || (udata == &wxlua_lreg_refs_key) || (udata == &wxlua_lreg_debug_refs_key) || (udata == &wxlua_lreg_classes_key) || (udata == &wxlua_lreg_derivedmethods_key) || (udata == &wxlua_lreg_wxluastate_key) || (udata == &wxlua_lreg_wxluabindings_key) || (udata == &wxlua_lreg_weakobjects_key) || (udata == &wxlua_lreg_gcobjects_key) || (udata == &wxlua_lreg_evtcallbacks_key) || (udata == &wxlua_lreg_windestroycallbacks_key) || (udata == &wxlua_lreg_callbaseclassfunc_key) || (udata == &wxlua_lreg_wxeventtype_key) || (udata == &wxlua_lreg_wxluastatedata_key) || (udata == &wxlua_lreg_regtable_key) || (udata == &wxlua_metatable_type_key) || (udata == &wxlua_lreg_topwindows_key) || (udata == &wxlua_metatable_wxluabindclass_key)) { const char* ss = *(const char**)udata; s += wxString::Format(wxT(" (%s)"), lua2wx(ss).c_str()); } } else // is full userdata { int wxl_type = wxluaT_type(L, stack_idx); if (wxlua_iswxuserdatatype(wxl_type)) { s += wxString::Format(wxT(" (wxltype %d)"), wxl_type); wxString wxltypeName(wxluaT_typename(L, wxl_type)); if (!wxltypeName.IsEmpty()) s += wxString::Format(wxT(" '%s'"), wxltypeName.c_str()); } } return s; }
// %override wxLua_function_type // %function int type(int wxluaarg_tag) static int LUACALL wxLua_function_type(lua_State *L) { int ltype = lua_type(L, 1); const char* ltypename = lua_typename(L, ltype); int wxl_type = wxluaT_type(L, 1); wxString wxltypeName = wxluaT_typename(L, wxl_type); // push the results lua_pushstring(L, wx2lua(wxltypeName)); lua_pushnumber(L, wxl_type); lua_pushstring(L, ltypename); lua_pushnumber(L, ltype); return 4; }
wxString wxLuaCheckStack::DumpTable(int stack_idx, const wxString& tablename, const wxString& msg, wxSortedArrayString& tableArray, int indent) { wxCHECK_MSG(m_luaState, wxEmptyString, wxT("Invalid lua_State")); lua_State* L = m_luaState; wxLuaState wxlState(L); wxString indentStr; wxString s; // We only do tables, return error message if (!lua_istable(L, stack_idx)) { s.Printf(wxT("wxLuaCheckStack::DumpTable(L=%p) stack idx %d is not a table.\n"), L, stack_idx); OutputMsg(s); return s; } if (indent == 0) { // First time through print header s.Printf(wxT("wxLuaCheckStack::DumpTable(L=%p) Table: '%s'\n"), L, tablename.c_str()); OutputMsg(s); } else if (indent > 10) { // Don't let things get out of hand... s.Printf(wxT("wxLuaCheckStack::DumpTable(L=%p) Table depth > 10! Truncating: '%s'\n"), L, tablename.c_str()); OutputMsg(s); return s; } else { indentStr = wxString(wxT(' '), indent*2) + wxT(">"); } wxString title = wxString::Format(wxT("%sTable Level %d : name '%s'\n"), indentStr.c_str(), indent, tablename.c_str()); s += title; OutputMsg(title); lua_pushvalue(L, stack_idx); // push the table to read the top of the stack lua_pushnil(L); while (lua_next(L, -2) != 0) { int keyType = 0, valueType = 0; wxString key, value; wxLuaDebugData::GetTypeValue(L, -2, &keyType, key); wxLuaDebugData::GetTypeValue(L, -1, &valueType, value); wxString info = wxString::Format(wxT("%s%-32s\t%-16s\t%-20s\t%-16s\n"), indentStr.c_str(), key.c_str(), wxluaT_typename(L, keyType).c_str(), value.c_str(), wxluaT_typename(L, valueType).c_str()); s += info; OutputMsg(info); if (tableArray.Index(value) == wxNOT_FOUND) { if (valueType == WXLUA_TTABLE) { tableArray.Add(value); s += DumpTable(lua_gettop(L), tablename + wxT(".") + key, msg, tableArray, indent+1); } else { tableArray.Add(value); } } lua_pop(L, 1); // pop value } lua_pop(L, 1); // pop pushed table return s; }
int wxLuaDebugData::EnumerateTable(lua_State* L, int tableRef, int nIndex, wxArrayInt& references) { wxCHECK_MSG(L, 0, wxT("Invalid lua_State")); wxCHECK_MSG(M_DEBUGREFDATA != NULL, 0, wxT("Invalid ref data")); int count = 0; int wxl_keytype = WXLUA_TNONE; int wxl_valuetype = WXLUA_TNONE; wxString value; wxString name; if (tableRef == LUA_GLOBALSINDEX) { lua_pushglobaltable(L); GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); // pop globals table Add(new wxLuaDebugItem(wxT("Globals"), WXLUA_TNONE, value, WXLUA_TTABLE, wxEmptyString, val_ref, 0, flag_type)); } #if LUA_VERSION_NUM < 502 // LUA_ENVIRONINDEX is no longer in 5.2 else if (tableRef == LUA_ENVIRONINDEX) { lua_pushvalue(L, LUA_ENVIRONINDEX); GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); // pop environment table Add(new wxLuaDebugItem(wxT("Environment"), WXLUA_TNONE, value, WXLUA_TTABLE, wxEmptyString, val_ref, 0, flag_type)); } #endif // LUA_VERSION_NUM < 502 else if (tableRef == LUA_REGISTRYINDEX) { lua_pushvalue(L, LUA_REGISTRYINDEX); GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); // pop registry table Add(new wxLuaDebugItem(wxT("Registry"), WXLUA_TNONE, value, WXLUA_TTABLE, wxEmptyString, val_ref, 0, flag_type)); } else { // push the table onto the stack to iterate through if (wxluaR_getref(L, tableRef, &wxlua_lreg_debug_refs_key)) { if (lua_isnil(L, -1)) { // assert so we don't crash mysteriously inside Lua on nil lua_pop(L, 1); // pop nil wxFAIL_MSG(wxT("Invalid wxLua debug reference")); return count; } // Check to see if this is a wxLua LUA_REGISTRYINDEX table void *lightuserdata_reg_key = NULL; lua_pushlightuserdata(L, &wxlua_lreg_regtable_key); // push key lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); // push value (table we're iterating) lua_rawget(L, -2); lightuserdata_reg_key = lua_touserdata(L, -1); // returns NULL for nil lua_pop(L, 2); // pop wxlua_lreg_regtable_key table and (nil or lightuserdata) // Check if this table/userdata has a metatable if (lua_getmetatable(L, -1)) // if no metatable then nothing is pushed { // get the type and value GetTypeValue(L, -1, &wxl_valuetype, value); int flag_type = 0; int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); // leading space so it's first when sorted Add(new wxLuaDebugItem(wxT(" __metatable"), WXLUA_TTABLE, value, wxl_valuetype, wxEmptyString, val_ref, nIndex, flag_type)); ++count; lua_pop(L, 1); // pop metatable } // start iterating if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2) != 0) { // value at -1, key at -2, table at -3 // get the key type and value int lua_key_type = GetTypeValue(L, -2, &wxl_keytype, name); // get the value type and value int lua_value_type = GetTypeValue(L, -1, &wxl_valuetype, value); // Handle items within the wxLua LUA_REGISTRYINDEX tables to give more information if (lightuserdata_reg_key != NULL) { if (lightuserdata_reg_key == &wxlua_lreg_types_key) { value += wxString::Format(wxT(" (%s)"), wxluaT_typename(L, (int)lua_tonumber(L, -2)).c_str()); } else if (lightuserdata_reg_key == &wxlua_lreg_classes_key) { wxLuaBindClass* wxlClass = (wxLuaBindClass*)lua_touserdata(L, -1); value += wxLuaBindClassString(wxlClass); } else if (lightuserdata_reg_key == &wxlua_lreg_wxluabindings_key) { wxLuaBinding* binding = (wxLuaBinding*)lua_touserdata(L, -2); name = wxString::Format(wxT("wxLuaBinding(%s) -> %s"), name.c_str(), binding->GetBindingName().c_str()); value += wxT(" = ") + binding->GetLuaNamespace(); } else if (lightuserdata_reg_key == &wxlua_lreg_evtcallbacks_key) { wxLuaEventCallback* wxlCallback = (wxLuaEventCallback*)lua_touserdata(L, -2); wxCHECK_MSG(wxlCallback, count, wxT("Invalid wxLuaEventCallback")); wxString s(wxlCallback->GetInfo()); name = s.BeforeFirst(wxT('|')); value = s.AfterFirst(wxT('|')); } else if (lightuserdata_reg_key == &wxlua_lreg_windestroycallbacks_key) { // only handle t[wxWindow*] = wxLuaWinDestroyCallback* wxLuaWinDestroyCallback* wxlDestroyCallBack = (wxLuaWinDestroyCallback*)lua_touserdata(L, -1); wxCHECK_MSG(wxlDestroyCallBack, count, wxT("Invalid wxLuaWinDestroyCallback")); wxString s(wxlDestroyCallBack->GetInfo()); name = s.BeforeFirst(wxT('|')); value = s.AfterFirst(wxT('|')); } else if (lightuserdata_reg_key == &wxlua_lreg_topwindows_key) { wxWindow* win = (wxWindow*)lua_touserdata(L, -2); name += wxT(" ") + wxString(win->GetClassInfo()->GetClassName()); } else if (lightuserdata_reg_key == &wxlua_lreg_gcobjects_key) { int wxl_type_ = (int)lua_tonumber(L, -1); name = wxString::Format(wxT("%s(%s)"), wxluaT_typename(L, wxl_type_).c_str(), name.c_str()); } else if (lightuserdata_reg_key == &wxlua_lreg_weakobjects_key) { wxString names_weak; // iterate the table of userdata lua_pushnil(L); while (lua_next(L, -2) != 0) { // value = -1, key = -2, table = -3 int wxl_type_weak = (int)lua_tonumber(L, -2); if (!names_weak.IsEmpty()) names_weak += wxT(", "); names_weak += wxString::Format(wxT("%s(%d)"), wxluaT_typename(L, wxl_type_weak).c_str(), wxl_type_weak); lua_pop(L, 1); // pop value, lua_next will pop key at end } name = wxString::Format(wxT("%s (%s)"), names_weak.c_str(), name.c_str()); } } // For these keys we know what is in the value to give more information if (lua_key_type == LUA_TLIGHTUSERDATA) { void* key = lua_touserdata(L, -2); if (key == &wxlua_lreg_wxeventtype_key) { wxEventType eventType = (wxEventType)lua_tonumber(L, -1); const wxLuaBindEvent* wxlEvent = wxLuaBinding::FindBindEvent(eventType); if (wxlEvent != NULL) { value = wxString::Format(wxT("%d = %s : %s"), eventType, lua2wx(wxlEvent->name).c_str(), wxluaT_typename(L, *wxlEvent->wxluatype).c_str()); } } else if (key == &wxlua_metatable_type_key) { value += wxString::Format(wxT(" (%s)"), wxluaT_typename(L, (int)lua_tonumber(L, -1)).c_str()); } else if (key == &wxlua_metatable_wxluabindclass_key) { wxLuaBindClass* wxlClass = (wxLuaBindClass*)lua_touserdata(L, -1); value += wxLuaBindClassString(wxlClass); } else if (key == &wxlua_lreg_debug_refs_key) { value += wxT(" Note: You cannot traverse refed tables"); } } // ---------------------------------------------------------- // Handle the key int key_flag_type = 0; int key_ref = LUA_NOREF; // don't ref anything in this table since it's already refed if ((lua_key_type == LUA_TTABLE) && (lightuserdata_reg_key != &wxlua_lreg_debug_refs_key)) { key_ref = RefTable(L, -2, &key_flag_type, WXLUA_DEBUGITEM_KEY_REF, references); } else if (lua_key_type == LUA_TUSERDATA) { if (lua_getmetatable(L, -2)) // doesn't push anything if nil { key_ref = RefTable(L, -2, &key_flag_type, WXLUA_DEBUGITEM_KEY_REF, references); lua_pop(L, 1); } } // only add the key if we refed it so it can be viewed in the stack dialog if (key_flag_type != 0) { Add(new wxLuaDebugItem(name, wxl_keytype, value, wxl_valuetype, wxEmptyString, key_ref, nIndex, key_flag_type)); ++count; } // ---------------------------------------------------------- // Handle the value int val_flag_type = 0; int val_ref = LUA_NOREF; // don't ref anything in this table since it's already refed if ((lua_value_type == LUA_TTABLE) && (lightuserdata_reg_key != &wxlua_lreg_debug_refs_key)) { val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); } else if (lua_value_type == LUA_TUSERDATA) { if (lua_getmetatable(L, -1)) // doesn't push anything if nil { val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references); lua_pop(L, 1); } } // Add the value, but not if the value doesn't expand and the key was already added if ((key_flag_type == 0) || ((key_flag_type != 0) && (val_flag_type != 0))) { Add(new wxLuaDebugItem(name, wxl_keytype, value, wxl_valuetype, wxEmptyString, val_ref, nIndex, val_flag_type)); ++count; } lua_pop(L, 1); // pop value, leave key } } lua_pop(L, 1); // remove reference } } return count; }
bool wxLuaDebugTarget::EvaluateExpr(int exprRef, const wxString &strExpr) // FIXME - check this code { wxString strResult(wxT("Error")); int nReference = LUA_NOREF; EnterLuaCriticalSection(); { lua_State* L = m_wxlState.GetLuaState(); if (wxStrpbrk(strExpr.c_str(), wxT(" ~=<>+-*/%(){}[]:;,.\"'")) != NULL) { // an expression int nOldTop = lua_gettop(L); wxLuaCharBuffer charbuf(strExpr); int nResult = luaL_loadbuffer(L, charbuf.GetData(), charbuf.Length(), "debug"); if (nResult == 0) nResult = lua_pcall(L, 0, LUA_MULTRET, 0); // call main if (nResult != 0) wxlua_pushwxString(L, wxlua_LUA_ERR_msg(nResult)); else if (lua_gettop(L) == nOldTop) lua_pushliteral(L, "OK"); nReference = m_wxlState.wxluaR_Ref(-1, &wxlua_lreg_refs_key); lua_settop(L, nOldTop); // throw out all return values } else { lua_Debug ar = INIT_LUA_DEBUG; int iLevel = 0; bool fFound = false; while (lua_getstack(L, iLevel++, &ar) != 0) { int iIndex = 0; wxString name = lua2wx(lua_getlocal(L, &ar, ++iIndex)); if (!name.IsEmpty()) { if (strExpr == name) { nReference = m_wxlState.wxluaR_Ref(-1, &wxlua_lreg_refs_key); fFound = true; break; } lua_pop(L, 1); } if (fFound) break; name = lua2wx(lua_getlocal(L, &ar, ++iIndex)); } if (!fFound) { int nOldTop = lua_gettop(L); lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushnil(L); while (lua_next(L, -2) != 0) { if (lua_type(L, -2) == LUA_TSTRING) { wxString name = lua2wx(lua_tostring(L, -2)); if (strExpr == name) { nReference = m_wxlState.wxluaR_Ref(-1, &wxlua_lreg_refs_key); // reference value lua_pop(L, 2); // pop key and value fFound = true; break; } } lua_pop(L, 1); // removes 'value'; } lua_settop(L, nOldTop); // the table of globals. } } if (m_wxlState.wxluaR_GetRef(nReference, &wxlua_lreg_refs_key)) { m_wxlState.wxluaR_Unref(nReference, &wxlua_lreg_refs_key); int wxl_type = 0; wxString value; wxLuaDebugData::GetTypeValue(L, -1, &wxl_type, value); strResult.Printf(wxT("%s : %s"), wxluaT_typename(L, wxl_type).c_str(), value.c_str()); lua_pop(L, 1); } } LeaveLuaCriticalSection(); return NotifyEvaluateExpr(exprRef, strResult); }