Python summary strings:
- you can use a Python script to write a summary string for data-types, in one of
three ways:
-P option and typing the script a line at a time
-s option and passing a one-line Python script
-F option and passing the name of a Python function
these options all work for the "type summary add" command
your Python code (if provided through -P or -s) is wrapped in a function
that accepts two parameters: valobj (a ValueObject) and dict (an LLDB
internal dictionary object). if you use -F and give a function name,
you're expected to define the function on your own and with the right
prototype. your function, however defined, must return a Python string
- test case for the Python summary feature
- a few quirks:
Python summaries cannot have names, and cannot use regex as type names
both issues will be fixed ASAP
major redesign of type summary code:
- type summary working with strings and type summary working with Python code
are two classes, with a common base class SummaryFormat
- SummaryFormat classes now are able to actively format objects rather than
just aggregating data
- cleaner code to print descriptions for summaries
the public API now exports a method to easily navigate a ValueObject hierarchy
New InputReaderEZ and PriorityPointerPair classes
Several minor fixes and improvements
llvm-svn: 135238
This commit is contained in:
@@ -34,6 +34,7 @@ using namespace lldb_private;
|
||||
|
||||
static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL;
|
||||
static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL;
|
||||
static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL;
|
||||
|
||||
|
||||
static int
|
||||
@@ -1140,6 +1141,117 @@ ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &func
|
||||
return ExecuteMultipleLines (function_def_string.c_str());
|
||||
}
|
||||
|
||||
// TODO move both GenerateTypeScriptFunction and GenerateBreakpointCommandCallbackData to actually
|
||||
// use this code to generate their functions
|
||||
bool
|
||||
ScriptInterpreterPython::GenerateFunction(std::string& signature, StringList &input, StringList &output)
|
||||
{
|
||||
int num_lines = input.GetSize ();
|
||||
if (num_lines == 0)
|
||||
return false;
|
||||
StreamString sstr;
|
||||
StringList auto_generated_function;
|
||||
auto_generated_function.AppendString (signature.c_str());
|
||||
auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
|
||||
auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
|
||||
auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
|
||||
auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
|
||||
// global dictionary.
|
||||
|
||||
// Wrap everything up inside the function, increasing the indentation.
|
||||
|
||||
for (int i = 0; i < num_lines; ++i)
|
||||
{
|
||||
sstr.Clear ();
|
||||
sstr.Printf (" %s", input.GetStringAtIndex (i));
|
||||
auto_generated_function.AppendString (sstr.GetData());
|
||||
}
|
||||
auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
|
||||
auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
|
||||
auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
|
||||
auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
|
||||
|
||||
// Verify that the results are valid Python.
|
||||
|
||||
if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// this implementation is identical to GenerateBreakpointCommandCallbackData (apart from the name
|
||||
// given to generated functions, of course)
|
||||
bool
|
||||
ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, StringList &output)
|
||||
{
|
||||
static int num_created_functions = 0;
|
||||
user_input.RemoveBlankLines ();
|
||||
int num_lines = user_input.GetSize ();
|
||||
StreamString sstr;
|
||||
|
||||
// Check to see if we have any data; if not, just return.
|
||||
if (user_input.GetSize() == 0)
|
||||
return false;
|
||||
|
||||
// Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
|
||||
// ValueObject as parameter to the function.
|
||||
|
||||
sstr.Printf ("lldb_autogen_python_type_print_func_%d", num_created_functions);
|
||||
++num_created_functions;
|
||||
std::string auto_generated_function_name = sstr.GetData();
|
||||
|
||||
sstr.Clear();
|
||||
StringList auto_generated_function;
|
||||
|
||||
// Create the function name & definition string.
|
||||
|
||||
sstr.Printf ("def %s (valobj, dict):", auto_generated_function_name.c_str());
|
||||
auto_generated_function.AppendString (sstr.GetData());
|
||||
|
||||
// Pre-pend code for setting up the session dictionary.
|
||||
|
||||
auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
|
||||
auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
|
||||
auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
|
||||
auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
|
||||
// global dictionary.
|
||||
|
||||
// Wrap everything up inside the function, increasing the indentation.
|
||||
|
||||
for (int i = 0; i < num_lines; ++i)
|
||||
{
|
||||
sstr.Clear ();
|
||||
sstr.Printf (" %s", user_input.GetStringAtIndex (i));
|
||||
auto_generated_function.AppendString (sstr.GetData());
|
||||
}
|
||||
|
||||
// Append code to clean up the global dictionary and update the session dictionary (all updates in the function
|
||||
// got written to the values in the global dictionary, not the session dictionary).
|
||||
|
||||
auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
|
||||
auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
|
||||
auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
|
||||
auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
|
||||
|
||||
// Verify that the results are valid Python.
|
||||
|
||||
if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
|
||||
return false;
|
||||
|
||||
// Store the name of the auto-generated function to be called.
|
||||
|
||||
output.AppendString (auto_generated_function_name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, StringList &output)
|
||||
{
|
||||
StringList input(oneliner);
|
||||
return GenerateTypeScriptFunction(input, output);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, StringList &callback_data)
|
||||
{
|
||||
@@ -1206,6 +1318,63 @@ ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
ScriptInterpreterPython::CallPythonScriptFunction (const char *python_function_name,
|
||||
lldb::ValueObjectSP valobj)
|
||||
{
|
||||
|
||||
if (!python_function_name || !(*python_function_name))
|
||||
return "<no function>";
|
||||
|
||||
if (!valobj.get())
|
||||
return "<no object>";
|
||||
|
||||
Target *target = valobj->GetUpdatePoint().GetTarget();
|
||||
|
||||
if (!target)
|
||||
return "<no target>";
|
||||
|
||||
Debugger &debugger = target->GetDebugger();
|
||||
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
|
||||
ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
|
||||
|
||||
if (!script_interpreter)
|
||||
return "<no python>";
|
||||
|
||||
std::string ret_val;
|
||||
|
||||
if (python_function_name
|
||||
&& *python_function_name)
|
||||
{
|
||||
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
|
||||
if (CurrentThreadHasPythonLock())
|
||||
{
|
||||
python_interpreter->EnterSession ();
|
||||
ret_val = g_swig_typescript_callback (python_function_name,
|
||||
python_interpreter->m_dictionary_name.c_str(),
|
||||
valobj);
|
||||
python_interpreter->LeaveSession ();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!GetPythonLock (1))
|
||||
fprintf (tmp_fh,
|
||||
"Python interpreter locked on another thread; waiting to acquire lock...\n");
|
||||
python_interpreter->EnterSession ();
|
||||
ret_val = g_swig_typescript_callback (python_function_name,
|
||||
python_interpreter->m_dictionary_name.c_str(),
|
||||
valobj);
|
||||
python_interpreter->LeaveSession ();
|
||||
ReleasePythonLock ();
|
||||
}
|
||||
}
|
||||
else
|
||||
return "<no function name>";
|
||||
|
||||
return ret_val;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::BreakpointCallbackFunction
|
||||
(
|
||||
@@ -1399,10 +1568,12 @@ ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
|
||||
|
||||
void
|
||||
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
|
||||
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback)
|
||||
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
|
||||
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback)
|
||||
{
|
||||
g_swig_init_callback = python_swig_init_callback;
|
||||
g_swig_breakpoint_callback = python_swig_breakpoint_callback;
|
||||
g_swig_breakpoint_callback = python_swig_breakpoint_callback;
|
||||
g_swig_typescript_callback = python_swig_typescript_callback;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user