1 /////////////////////////////////////////////////////////////////////////////
2 // Purpose:     Lua and wxLua debugging code
3 // Author:      J. Winwood, John Labenski
4 // Created:     June 2003
5 // Copyright:   (c) 2012 John Labenski, 2002 Lomtick Software. All rights reserved.
6 // Licence:     wxWidgets licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 #ifndef WX_LUA_DEBUG_H
10 #define WX_LUA_DEBUG_H
11 
12 #include <wx/dynarray.h>
13 #include <wx/treectrl.h> // for wxTreeItemData
14 
15 #include "wxlua/debug/wxluadebugdefs.h"
16 #include "wxlua/wxlstate.h"
17 
18 class WXDLLIMPEXP_WXLUADEBUG wxLuaDebugData;
19 
20 // ----------------------------------------------------------------------------
21 // wxLuaDebugItem - A class to store an item from Lua for wxLuaDebugData
22 //
23 // It is typically used to store table[key] = value pair info. However it may
24 // be used to store stack information as well.
25 // ----------------------------------------------------------------------------
26 
27 enum wxLuaDebugItem_Type
28 {
29     WXLUA_DEBUGITEM_LOCALS    = 0x0100, // This wxLuaDebugItem is the parent for local variables
30 
31     WXLUA_DEBUGITEM_EXPANDED  = 0x0200, // for wxLuaStackDialog
32 
33     WXLUA_DEBUGITEM_IS_REFED  = 0x1000, // This item was created with a new
34                                         // wxluaR_ref() rather than using an existing one.
35     WXLUA_DEBUGITEM_KEY_REF   = 0x2000, // The ref is for the key
36     WXLUA_DEBUGITEM_VALUE_REF = 0x4000, // The ref is for the value
37 };
38 
39 class WXDLLIMPEXP_WXLUADEBUG wxLuaDebugItem
40 {
41 public:
42     wxLuaDebugItem(const wxLuaDebugItem &debugDataItem);
43     wxLuaDebugItem(const wxString &itemKey,   int itemKeyType,
44                    const wxString &itemValue, int itemValueType,
45                    const wxString &itemSource,
46                    int lua_ref, int idx = 0, int flag = 0);
47 
48     // The key has the typical meaning of the key in a Lua table
GetKey()49     wxString GetKey() const             { return m_itemKey; }
GetKeyType()50     int      GetKeyType() const         { return m_itemKeyType; }
GetKeyTypeString()51     wxString GetKeyTypeString() const   { return wxluaT_typename(NULL, m_itemKeyType); }
52 
53     // The value has the typical meaning of the value for the key in a Lua table
GetValue()54     wxString GetValue() const           { return m_itemValue; }
GetValueType()55     int      GetValueType() const       { return m_itemValueType; }
GetValueTypeString()56     wxString GetValueTypeString() const { return wxluaT_typename(NULL, m_itemValueType); }
57 
58     // The lua_Debug.source value when enumerating the stack or a stack item
GetSource()59     wxString GetSource() const          { return m_itemSource; }
60 
GetRef()61     int      GetRef() const             { return m_lua_ref; }  // wxluaR_ref() reference
GetIndex()62     int      GetIndex() const           { return m_index; }    // stack index or table level index
GetFlag()63     int      GetFlag() const            { return m_flag; }     // see wxLuaDebugItem_Type
GetFlagBit(int mask)64     bool     GetFlagBit(int mask) const { return WXLUA_HASBIT(m_flag, mask); }
65 
66     // If GetFlagBit(WXLUA_DEBUGITEM_KEY_REFED) try to convert GetKey() to a number
67     // else if GetFlagBit(WXLUA_DEBUGITEM_VALUE_REFED) try to convert GetValue() to a number
68     // Asserts if neither or both of the bits are set.
69     bool     GetRefPtr(wxUIntPtr& ptr) const;
70 
SetFlag(int flag)71     void     SetFlag(int flag)             { m_flag = flag; }
SetFlagBit(int bit,bool set)72     void     SetFlagBit(int bit, bool set) { m_flag = WXLUA_SETBIT(m_flag, bit, set); }
SetRef(int lua_ref)73     void     SetRef(int lua_ref)           { m_lua_ref = lua_ref; } // only if you've wxluaR_unref()ed it
74 
75     // Get a human readable string for debugging
ToString()76     wxString ToString() const
77     {
78         return wxString::Format(wxT("Key: '%s' KeyType: %d '%s' Value: '%s' ValueType: %d '%s' Ref: %d Idx: %d Flag: %x HasSrc: %d"),
79             m_itemKey.c_str(), m_itemKeyType, GetKeyTypeString().c_str(),
80             m_itemValue.c_str(), m_itemValueType, GetValueTypeString().c_str(),
81             m_lua_ref, m_index, m_flag, (int)!m_itemSource.IsEmpty());
82     }
83 
84     // implementation
85 
86     wxString   m_itemKey;
87     int        m_itemKeyType;
88     wxString   m_itemValue;
89     int        m_itemValueType;
90     wxString   m_itemSource;
91     int        m_lua_ref;
92     int        m_index;
93     int        m_flag;
94 };
95 
96 #if defined(WXMAKINGDLL_WXLUADEBUG) || defined(WXUSINGDLL)
97     WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxLuaDebugItem *, wxLuaDebugItemArray, WXDLLIMPEXP_WXLUADEBUG);
98 #else
99     WX_DEFINE_SORTED_ARRAY(wxLuaDebugItem *, wxLuaDebugItemArray);
100 #endif
101 
102 // ----------------------------------------------------------------------------
103 // wxLuaDebugData - a wxObject ref counted container for a wxLuaDebugItemArray
104 // The destructor deletes the array items.
105 // ----------------------------------------------------------------------------
106 
107 // an invalid wxLuaDebugData for comparison (like wxNullBitmap)
108 extern WXDLLIMPEXP_DATA_WXLUADEBUG(wxLuaDebugData) wxNullLuaDebugData;
109 
110 class WXDLLIMPEXP_WXLUADEBUG wxLuaDebugData : public wxObject
111 {
112 public:
113     wxLuaDebugData(bool create);
wxLuaDebugData(const wxLuaDebugData & debugData)114     wxLuaDebugData(const wxLuaDebugData &debugData) { Ref(debugData); }
115 
~wxLuaDebugData()116     virtual ~wxLuaDebugData() {} // make gcc happy even though it's not used
117 
118     // Has this been created with its ref data?
Ok()119     bool Ok() const { return (m_refData != NULL); }
120 
121     // Get the data array, please use safe array access functions if possible
122     wxLuaDebugItemArray* GetArray();
123     const wxLuaDebugItemArray* GetArray() const;
124 
125     // wxArray functions mapped to the internal array w/ error checking
126     //   The wxLuaDebugItem items added must be created with 'new' and
127     //   will be deleted when this class is destroyed.
128     size_t GetCount() const;
129     wxLuaDebugItem* Item(size_t index) const;
130     void Add(wxLuaDebugItem* item);
131 
132     //-------------------------------------------------------------------------
133 
134     // fill this with the stack entries for the wxLuaState
135     //   returns the number of stack entries added
136     int EnumerateStack(lua_State* L);
137     // fill this with the locals from a particular stack frame, if an item on the stack is a
138     //   table then add a reference to it in the references array
139     int EnumerateStackEntry(lua_State* L, int stack_frame, wxArrayInt& references);
140     // Fill this with the name and value of items in a table at the given reference
141     // in the wxlua_lreg_debug_refs_key in the LUA_REGISTRYINDEX.
142     // nRef may also be LUA_GLOBALSINDEX and LUA_REGISTRYINDEX.
143     // If the table has a sub table then add a reference to it to the references array.
144     int EnumerateTable(lua_State* L, int nRef, int nEntry, wxArrayInt& references);
145 
146     //-------------------------------------------------------------------------
147     // These functions are static to allow them to be used in other places to
148     //    give a consistent feel to the display of Lua values.
149 
150     // Get information about the item at the 'stack_idx'. Returns the lua_type(L, stack_idx),
151     //   fills 'wxl_type' with the WXLUA_TXXX type and 'value' with a human readable value.
152     static int GetTypeValue(lua_State *L, int stack_idx, int* wxl_type, wxString& value);
153     // Get a wxString description about the table at the stack_idx in the Lua stack
154     static wxString GetTableInfo(lua_State *L, int stack_idx);
155     // Get a wxString description about user data at the stack_idx in the Lua stack
156     //  if full then try to look up the name of the user data from the bindings
157     static wxString GetUserDataInfo(lua_State *L, int stack_idx, bool full_userdata);
158 
159     //-------------------------------------------------------------------------
160 
161     // Make a full copy of the array and return it.
162     wxLuaDebugData Copy() const;
163 
164     // Ref this table if it hasn't been refed already, returns ref # or LUA_NOREF if not refed
165     int RefTable(lua_State* L, int stack_idx, int* flag_type, int extra_flag, wxArrayInt& references);
166 
167     // Sorting function for the wxLuaDebugItemArray, sorts by name
168     static int SortFunction(wxLuaDebugItem *elem1, wxLuaDebugItem *elem2 );
169 
170     // operators
171     bool operator == (const wxLuaDebugData& debugData) const
172         { return m_refData == debugData.m_refData; }
173     bool operator != (const wxLuaDebugData& debugData) const
174         { return m_refData != debugData.m_refData; }
175 
176     wxLuaDebugData& operator = (const wxLuaDebugData& debugData)
177     {
178         if ( (*this) != debugData )
179             Ref(debugData);
180         return *this;
181     }
182 };
183 
184 // ----------------------------------------------------------------------------
185 // wxLuaCheckStack - Dump the contents of the lua_State for debugging
186 // ----------------------------------------------------------------------------
187 
188 class WXDLLIMPEXP_WXLUADEBUG wxLuaCheckStack
189 {
190 public:
191     // Create a instance, remembers lua_gettop(), 'msg' can be used to add
192     // information about where or why this was created.
193     // If 'print_to_console' then all functions below that return a string will also
194     // print to the console as well.
195     wxLuaCheckStack(lua_State* L, const wxString &msg = wxEmptyString, bool print_to_console = true);
196     // Prints out the starting top and ending top if 'print_to_console' in constructor
197     ~wxLuaCheckStack();
198 
199     // Returns a string comparing the starting and current lua_gettop() with additional msg
200     wxString TestStack(const wxString &msg = wxEmptyString);
201 
202     // Returns a string of the current items on the stack with their types.
203     wxString DumpStack(const wxString& msg = wxEmptyString);
204 
205     // Returns a string of all of the global variables and subtables with additional msg.
206     wxString DumpGlobals(const wxString& msg = wxEmptyString);
207     // Dump the table and its subtables from the globals index with additional msg.
208     // The name may be of the form "table1.subtable2.subtable3..."
209     wxString DumpTable(const wxString& tableName, const wxString& msg = wxEmptyString);
210     // Dump the table and its subtables at the stack_idx with additional msg.
211     wxString DumpTable(int stack_idx, const wxString& msg = wxEmptyString);
212 
213     // Dump the contents of the table at the stack_idx to a string. 'tablename' and 'msg' are
214     // for informational messages, 'tableArray' is used to avoid recursion and should be empty
215     // for the initial call, and 'indent' is used to track indentation level for each subtable.
216     wxString DumpTable(int stack_idx, const wxString& tablename, const wxString& msg, wxSortedArrayString& tableArray, int indent);
217 
218     // Print a message to the console if 'print_to_console' in constructor.
219     void OutputMsg(const wxString& msg) const;
220 
221     // implementation
222 
223     lua_State* m_luaState;
224     wxString   m_msg;
225     int        m_top;
226     bool       m_print_to_console;
227 };
228 
229 #endif // WX_LUA_DEBUG_H
230