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

git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@135238 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/lldb/API/SBValue.h b/include/lldb/API/SBValue.h
index 40a4612..9fce5bc 100644
--- a/include/lldb/API/SBValue.h
+++ b/include/lldb/API/SBValue.h
@@ -167,6 +167,10 @@
     // classes.
     lldb::SBValue
     GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dynamic);
+    
+    // Expands nested expressions like .a->b[0].c[1]->d
+    lldb::SBValue
+    GetValueForExpressionPath(const char* expr_path);
 
     uint32_t
     GetNumChildren ();
@@ -190,12 +194,12 @@
     bool
     GetExpressionPath (lldb::SBStream &description, bool qualify_cxx_base_classes);
 
+    SBValue (const lldb::ValueObjectSP &value_sp);
+    
 protected:
     friend class SBValueList;
     friend class SBFrame;
 
-    SBValue (const lldb::ValueObjectSP &value_sp);
-
 #ifndef SWIG
 
     // Mimic shared pointer...
diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h
index f43b842..ea9a648 100644
--- a/include/lldb/Core/Debugger.h
+++ b/include/lldb/Core/Debugger.h
@@ -576,8 +576,6 @@
         static uint32_t
         GetCount();
     };
-
-    
 };
 
 } // namespace lldb_private
diff --git a/include/lldb/Core/Error.h b/include/lldb/Core/Error.h
index a36d842..a0476c8 100644
--- a/include/lldb/Core/Error.h
+++ b/include/lldb/Core/Error.h
@@ -69,6 +69,9 @@
     explicit
     Error (ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric);
 
+    explicit
+    Error (const char* err_str);
+    
     Error (const Error &rhs);
     //------------------------------------------------------------------
     /// Assignment operator.
diff --git a/include/lldb/Core/FormatManager.h b/include/lldb/Core/FormatManager.h
index f1bd52c..1fc4756 100644
--- a/include/lldb/Core/FormatManager.h
+++ b/include/lldb/Core/FormatManager.h
@@ -50,8 +50,10 @@
 #include "lldb/Core/UserID.h"
 #include "lldb/Core/UserSettingsController.h"
 #include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Platform.h"
+#include "lldb/Target/StackFrame.h"
 #include "lldb/Target/TargetList.h"
 
 namespace lldb_private {
@@ -67,8 +69,263 @@
     
 };
 
+struct ValueFormat
+{
+    bool m_cascades;
+    bool m_skip_pointers;
+    bool m_skip_references;
+    lldb::Format m_format;
+    ValueFormat (lldb::Format f = lldb::eFormatInvalid,
+                 bool casc = false,
+                 bool skipptr = false,
+                 bool skipref = false) : 
+    m_cascades(casc),
+    m_skip_pointers(skipptr),
+    m_skip_references(skipref),
+    m_format (f)
+    {
+    }
+    
+    typedef lldb::SharedPtr<ValueFormat>::Type SharedPointer;
+    typedef bool(*ValueCallback)(void*, const char*, const ValueFormat::SharedPointer&);
+    
+    ~ValueFormat()
+    {
+    }
+    
+    bool
+    Cascades()
+    {
+        return m_cascades;
+    }
+    bool
+    SkipsPointers()
+    {
+        return m_skip_pointers;
+    }
+    bool
+    SkipsReferences()
+    {
+        return m_skip_references;
+    }
+    
+    lldb::Format
+    GetFormat()
+    {
+        return m_format;
+    }
+    
+    std::string
+    FormatObject(lldb::ValueObjectSP object)
+    {
+        if (!object.get())
+            return "NULL";
+        
+        StreamString sstr;
+        
+        if (ClangASTType::DumpTypeValue (object->GetClangAST(),            // The clang AST
+                                         object->GetClangType(),           // The clang type to display
+                                         &sstr,
+                                         m_format,                          // Format to display this type with
+                                         object->GetDataExtractor(),       // Data to extract from
+                                         0,                                // Byte offset into "data"
+                                         object->GetByteSize(),            // Byte size of item in "data"
+                                         object->GetBitfieldBitSize(),     // Bitfield bit size
+                                         object->GetBitfieldBitOffset()))  // Bitfield bit offset
+            return (sstr.GetString());
+        else
+        {
+            return ("unsufficient data for value");
+        }
+        
+    }
+    
+};
+
 struct SummaryFormat
 {
+    bool m_cascades;
+    bool m_skip_pointers;
+    bool m_skip_references;
+    bool m_dont_show_children;
+    bool m_dont_show_value;
+    bool m_show_members_oneliner;
+    
+    SummaryFormat(bool casc = false,
+                  bool skipptr = false,
+                  bool skipref = false,
+                  bool nochildren = true,
+                  bool novalue = true,
+                  bool oneliner = false) :
+    m_cascades(casc),
+    m_skip_pointers(skipptr),
+    m_skip_references(skipref),
+    m_dont_show_children(nochildren),
+    m_dont_show_value(novalue),
+    m_show_members_oneliner(oneliner)
+    {
+    }
+    
+    bool
+    Cascades()
+    {
+        return m_cascades;
+    }
+    bool
+    SkipsPointers()
+    {
+        return m_skip_pointers;
+    }
+    bool
+    SkipsReferences()
+    {
+        return m_skip_references;
+    }
+    
+    bool
+    DoesPrintChildren() const
+    {
+        return !m_dont_show_children;
+    }
+    
+    bool
+    DoesPrintValue() const
+    {
+        return !m_dont_show_value;
+    }
+    
+    bool
+    IsOneliner() const
+    {
+        return m_show_members_oneliner;
+    }
+    
+    virtual
+    ~SummaryFormat()
+    {
+    }
+    
+    virtual std::string
+    FormatObject(lldb::ValueObjectSP object) = 0;
+    
+    virtual std::string
+    GetDescription() = 0;
+    
+    typedef lldb::SharedPtr<SummaryFormat>::Type SharedPointer;
+    typedef bool(*SummaryCallback)(void*, const char*, const SummaryFormat::SharedPointer&);
+    typedef bool(*RegexSummaryCallback)(void*, lldb::RegularExpressionSP, const SummaryFormat::SharedPointer&);
+    
+};
+
+// simple string-based summaries, using ${var to show data
+struct StringSummaryFormat : public SummaryFormat
+{
+    std::string m_format;
+    
+    StringSummaryFormat(bool casc = false,
+                        bool skipptr = false,
+                        bool skipref = false,
+                        bool nochildren = true,
+                        bool novalue = true,
+                        bool oneliner = false,
+                        std::string f = "") :
+    SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner),
+    m_format(f)
+    {
+    }
+    
+    std::string
+    GetFormat()
+    {
+        return m_format;
+    }
+    
+    virtual
+    ~StringSummaryFormat()
+    {
+    }
+    
+    virtual std::string
+    FormatObject(lldb::ValueObjectSP object);
+    
+    virtual std::string
+    GetDescription()
+    {
+        StreamString sstr;
+        sstr.Printf ("`%s`%s%s%s%s%s%s\n",      m_format.c_str(),
+                                                m_cascades ? "" : " (not cascading)",
+                                                m_dont_show_children ? "" : " (show children)",
+                                                m_dont_show_value ? " (hide value)" : "",
+                                                m_show_members_oneliner ? " (one-line printout)" : "",
+                                                m_skip_pointers ? " (skip pointers)" : "",
+                                                m_skip_references ? " (skip references)" : "");
+        return sstr.GetString();
+    }
+        
+};
+    
+// Python-based summaries, running script code to show data
+struct ScriptSummaryFormat : public SummaryFormat
+{
+    std::string m_function_name;
+    std::string m_python_script;
+    
+    ScriptSummaryFormat(bool casc = false,
+                        bool skipptr = false,
+                        bool skipref = false,
+                        bool nochildren = true,
+                        bool novalue = true,
+                        bool oneliner = false,
+                        std::string fname = "",
+                        std::string pscri = "") :
+    SummaryFormat(casc,skipptr,skipref,nochildren,novalue,oneliner),
+    m_function_name(fname),
+    m_python_script(pscri)
+    {
+    }
+    
+    std::string
+    GetFunctionName()
+    {
+        return m_function_name;
+    }
+    
+    std::string
+    GetPythonScript()
+    {
+        return m_python_script;
+    }
+    
+    virtual
+    ~ScriptSummaryFormat()
+    {
+    }
+    
+    virtual std::string
+    FormatObject(lldb::ValueObjectSP object)
+    {
+        return std::string(ScriptInterpreterPython::CallPythonScriptFunction(m_function_name.c_str(),
+                                                                             object).c_str());
+    }
+    
+    virtual std::string
+    GetDescription()
+    {
+        StreamString sstr;
+        sstr.Printf ("%s%s%s\n%s\n",      m_cascades ? "" : " (not cascading)",
+                                          m_skip_pointers ? " (skip pointers)" : "",
+                                          m_skip_references ? " (skip references)" : "",
+                                          m_python_script.c_str());
+        return sstr.GetString();
+
+    }
+        
+    typedef lldb::SharedPtr<ScriptSummaryFormat>::Type SharedPointer;
+
+};
+    
+/*struct SummaryFormat
+{
     std::string m_format;
     bool m_dont_show_children;
     bool m_dont_show_value;
@@ -116,32 +373,35 @@
     typedef bool(*RegexSummaryCallback)(void*, lldb::RegularExpressionSP, const SummaryFormat::SharedPointer&);
     
 };
-
-struct ValueFormat
+    
+struct ScriptFormat
 {
-    lldb::Format m_format;
+    std::string m_function_name;
+    std::string m_python_script;
     bool m_cascades;
     bool m_skip_references;
     bool m_skip_pointers;
-    ValueFormat (lldb::Format f = lldb::eFormatInvalid,
-                 bool c = false,
-                 bool skipptr = false,
-                 bool skipref = false) : 
-    m_format (f), 
+    ScriptFormat (std::string n,
+                  std::string s = "",
+                  bool c = false,
+                  bool skipptr = false,
+                  bool skipref = false) : 
+    m_function_name (n),
+    m_python_script(s),
     m_cascades (c),
     m_skip_references(skipref),
     m_skip_pointers(skipptr)
     {
     }
     
-    typedef lldb::SharedPtr<ValueFormat>::Type SharedPointer;
-    typedef bool(*ValueCallback)(void*, const char*, const ValueFormat::SharedPointer&);
+    typedef lldb::SharedPtr<ScriptFormat>::Type SharedPointer;
+    typedef bool(*ScriptCallback)(void*, const char*, const ScriptFormat::SharedPointer&);
     
-    ~ValueFormat()
+    ~ScriptFormat()
     {
     }
     
-};
+};*/
 
 template<typename KeyType, typename ValueType>
 class FormatNavigator;
@@ -457,11 +717,13 @@
     typedef FormatNavigator<const char*, ValueFormat> ValueNavigator;
     typedef FormatNavigator<const char*, SummaryFormat> SummaryNavigator;
     typedef FormatNavigator<lldb::RegularExpressionSP, SummaryFormat> RegexSummaryNavigator;
+    typedef FormatNavigator<const char*, SummaryFormat> ScriptNavigator;
     
     typedef ValueNavigator::MapType ValueMap;
     typedef SummaryNavigator::MapType SummaryMap;
     typedef RegexSummaryNavigator::MapType RegexSummaryMap;
     typedef FormatMap<const char*, SummaryFormat> NamedSummariesMap;
+    typedef ScriptNavigator::MapType ScriptMap;
     
     ValueNavigator m_value_nav;
     SummaryNavigator m_summary_nav;
@@ -469,6 +731,8 @@
     
     NamedSummariesMap m_named_summaries_map;
     
+    ScriptNavigator m_script_nav;
+    
     uint32_t m_last_revision;
     
 public:
@@ -478,6 +742,7 @@
     m_summary_nav(this),
     m_regex_summary_nav(this),
     m_named_summaries_map(this),
+    m_script_nav(this),
     m_last_revision(0)
     {
     }
@@ -487,6 +752,7 @@
     SummaryNavigator& Summary() { return m_summary_nav; }
     RegexSummaryNavigator& RegexSummary() { return m_regex_summary_nav; }
     NamedSummariesMap& NamedSummary() { return m_named_summaries_map; }
+    ScriptNavigator& Script() { return m_script_nav; }
     
     static bool
     GetFormatFromCString (const char *format_cstr,
diff --git a/include/lldb/Core/InputReader.h b/include/lldb/Core/InputReader.h
index c1658a2..e1cc6aa 100644
--- a/include/lldb/Core/InputReader.h
+++ b/include/lldb/Core/InputReader.h
@@ -12,7 +12,7 @@
 
 #include "lldb/lldb-public.h"
 #include "lldb/lldb-enumerations.h"
-#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
 #include "lldb/Host/Predicate.h"
 
 
@@ -27,6 +27,31 @@
                                 lldb::InputReaderAction notification,
                                 const char *bytes, 
                                 size_t bytes_len);
+    
+    struct HandlerData
+    {
+        InputReader& reader;
+        const char *bytes;
+        size_t bytes_len;
+        void* baton;
+        
+        HandlerData(InputReader& r,
+                    const char* b,
+                    size_t l,
+                    void* t) : 
+        reader(r),
+        bytes(b),
+        bytes_len(l),
+        baton(t)
+        {
+        }
+        
+        lldb::StreamSP
+        GetOutStream();
+        
+        bool
+        GetBatchMode();
+    };
 
     InputReader (Debugger &debugger);
 
@@ -41,6 +66,41 @@
                 const char *prompt,
                 bool echo);
     
+    virtual Error Initialize(void* baton,
+                             lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine,
+                             const char* end_token = "DONE",
+                             const char *prompt = "> ",
+                             bool echo = true)
+    {
+        return Error("unimplemented");
+    }
+    
+    // to use these handlers instead of the Callback function, you must subclass
+    // InputReaderEZ, and redefine the handlers for the events you care about
+    virtual void
+    ActivateHandler(HandlerData&) {}
+    
+    virtual void
+    DeactivateHandler(HandlerData&) {}
+    
+    virtual void
+    ReactivateHandler(HandlerData&) {}
+    
+    virtual void
+    AsynchronousOutputWrittenHandler(HandlerData&) {}
+    
+    virtual void
+    GotTokenHandler(HandlerData&) {}
+    
+    virtual void
+    InterruptHandler(HandlerData&) {}
+    
+    virtual void
+    EOFHandler(HandlerData&) {}
+    
+    virtual void
+    DoneHandler(HandlerData&) {}
+    
     bool
     IsDone () const
     {
diff --git a/include/lldb/Core/InputReaderEZ.h b/include/lldb/Core/InputReaderEZ.h
new file mode 100644
index 0000000..95f6af9
--- /dev/null
+++ b/include/lldb/Core/InputReaderEZ.h
@@ -0,0 +1,81 @@
+//===-- InputReaderEZ.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_InputReaderEZ_h_
+#define liblldb_InputReaderEZ_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Host/Predicate.h"
+
+
+namespace lldb_private {
+
+class InputReaderEZ : public InputReader
+{
+
+private:
+    
+    static size_t Callback_Impl(void *baton, 
+                         InputReader &reader, 
+                         lldb::InputReaderAction notification,
+                         const char *bytes, 
+                         size_t bytes_len);    
+public:
+
+    InputReaderEZ (Debugger &debugger) :
+    InputReader(debugger)
+    {}
+
+    virtual
+    ~InputReaderEZ ();
+
+    virtual Error Initialize(void* baton,
+                             lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine,
+                             const char* end_token = "DONE",
+                             const char *prompt = "> ",
+                             bool echo = true);
+    
+    virtual void
+    ActivateHandler(HandlerData&) {}
+    
+    virtual void
+    DeactivateHandler(HandlerData&) {}
+    
+    virtual void
+    ReactivateHandler(HandlerData&) {}
+    
+    virtual void
+    AsynchronousOutputWrittenHandler(HandlerData&) {}
+    
+    virtual void
+    GotTokenHandler(HandlerData&) {}
+    
+    virtual void
+    InterruptHandler(HandlerData&) {}
+    
+    virtual void
+    EOFHandler(HandlerData&) {}
+    
+    virtual void
+    DoneHandler(HandlerData&) {}
+    
+protected:
+    friend class Debugger;
+
+private:
+    DISALLOW_COPY_AND_ASSIGN (InputReaderEZ);
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_InputReaderEZ_h_
diff --git a/include/lldb/Core/StringList.h b/include/lldb/Core/StringList.h
index b080919..c4edb82 100644
--- a/include/lldb/Core/StringList.h
+++ b/include/lldb/Core/StringList.h
@@ -68,7 +68,17 @@
 
     size_t
     SplitIntoLines (const char *lines, size_t len);
+    
+    std::string
+    CopyList(const char* item_preamble = NULL,
+             const char* items_sep = "\n");
+    
+    StringList&
+    operator << (const char* str);
 
+    StringList&
+    operator << (StringList strings);
+        
 private:
 
     STLStringArray m_strings;
diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h
index 87f41d9..d7e39de 100644
--- a/include/lldb/Core/ValueObject.h
+++ b/include/lldb/Core/ValueObject.h
@@ -27,6 +27,7 @@
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/ExecutionContextScope.h"
 #include "lldb/Target/StackID.h"
+#include "lldb/Utility/PriorityPointerPair.h"
 #include "lldb/Utility/SharedCluster.h"
 
 namespace lldb_private {
@@ -75,7 +76,8 @@
     {
         eDisplayValue = 1,
         eDisplaySummary,
-        eDisplayLanguageSpecific
+        eDisplayLanguageSpecific,
+        eDisplayLocation
     };
     
     enum ExpressionPathScanEndReason
@@ -731,8 +733,8 @@
     lldb::Format            m_format;
     uint32_t                m_last_format_mgr_revision;
     lldb::SummaryFormatSP   m_last_summary_format;
-    lldb::ValueFormatSP     m_last_value_format;
     lldb::SummaryFormatSP   m_forced_summary_format;
+    lldb::ValueFormatSP     m_last_value_format;
     lldb::user_id_t         m_user_id_of_forced_summary;
     bool                m_value_is_valid:1,
                         m_value_did_change:1,
@@ -802,6 +804,9 @@
 
     void
     SetValueIsValid (bool valid);
+    
+    void
+    ClearUserVisibleData();
 
 public:
     lldb::addr_t
diff --git a/include/lldb/Interpreter/ScriptInterpreter.h b/include/lldb/Interpreter/ScriptInterpreter.h
index 438222c..38ac00e 100644
--- a/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/include/lldb/Interpreter/ScriptInterpreter.h
@@ -26,6 +26,13 @@
                                                     const char *session_dictionary_name,
                                                     const lldb::StackFrameSP& frame_sp,
                                                     const lldb::BreakpointLocationSP &bp_loc_sp);
+    
+    typedef 
+    
+    typedef std::string (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
+                                                                 const char *session_dictionary_name,
+                                                                 const lldb::ValueObjectSP& valobj_sp);
+
     typedef enum
     {
         eCharPtr,
@@ -77,6 +84,25 @@
     {
         return false;
     }
+    
+    virtual bool
+    GenerateTypeScriptFunction (StringList &input, StringList &output)
+    {
+        return false;
+    }
+    
+    // use this if the function code is just a one-liner script
+    virtual bool
+    GenerateTypeScriptFunction (const char* oneliner, StringList &output)
+    {
+        return false;
+    }
+    
+    virtual bool
+    GenerateFunction(std::string& signature, StringList &input, StringList &output)
+    {
+        return false;
+    }
 
     virtual void 
     CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
@@ -104,7 +130,8 @@
     
     static void
     InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
-                           SWIGBreakpointCallbackFunction python_swig_breakpoint_callback);
+                           SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
+                           SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback);
 
     static void
     TerminateInterpreter ();
diff --git a/include/lldb/Interpreter/ScriptInterpreterPython.h b/include/lldb/Interpreter/ScriptInterpreterPython.h
index 4b1c38d..5d33e79 100644
--- a/include/lldb/Interpreter/ScriptInterpreterPython.h
+++ b/include/lldb/Interpreter/ScriptInterpreterPython.h
@@ -50,6 +50,16 @@
     ExportFunctionDefinitionToInterpreter (StringList &function_def);
 
     bool
+    GenerateTypeScriptFunction (StringList &input, StringList &output);
+    
+    // use this if the function code is just a one-liner script
+    bool
+    GenerateTypeScriptFunction (const char* oneliner, StringList &output);
+    
+    bool
+    GenerateFunction(std::string& signature, StringList &input, StringList &output);
+    
+    bool
     GenerateBreakpointCommandCallbackData (StringList &input, StringList &output);
 
     static size_t
@@ -64,6 +74,10 @@
                                 StoppointCallbackContext *context, 
                                 lldb::user_id_t break_id,
                                 lldb::user_id_t break_loc_id);
+    
+    static std::string
+    CallPythonScriptFunction (const char *python_function_name,
+                              lldb::ValueObjectSP valobj);
 
     void
     CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
@@ -88,7 +102,8 @@
 
     static void
     InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
-                           SWIGBreakpointCallbackFunction python_swig_breakpoint_callback);
+                           SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
+                           SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback);
 
 protected:
 
diff --git a/include/lldb/Utility/PriorityPointerPair.h b/include/lldb/Utility/PriorityPointerPair.h
new file mode 100644
index 0000000..949173d
--- /dev/null
+++ b/include/lldb/Utility/PriorityPointerPair.h
@@ -0,0 +1,150 @@
+//===-- PriorityPointerPair.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_PriorityPointerPair_h_
+#define liblldb_PriorityPointerPair_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Utility/SharingPtr.h"
+
+namespace lldb_utility {
+
+//----------------------------------------------------------------------
+// A prioritized pair of SharedPtr<T>. One of the two pointers is high
+// priority, the other is low priority.
+// The Get() method always returns high, if *high != NULL,
+// otherwise, low is returned (even if *low == NULL)
+//----------------------------------------------------------------------
+
+template<typename T>
+class PriorityPointerPair
+{
+public:
+    
+    typedef T& reference_type;
+    typedef T* pointer_type;
+    
+    typedef typename lldb::SharedPtr<T>::Type T_SP;
+    
+    PriorityPointerPair() : 
+    m_high(),
+    m_low()
+    {}
+    
+    PriorityPointerPair(pointer_type high,
+                        pointer_type low) : 
+    m_high(high),
+    m_low(low)
+    {}
+
+    PriorityPointerPair(pointer_type low) : 
+    m_high(),
+    m_low(low)
+    {}
+
+    PriorityPointerPair(T_SP& high,
+                        T_SP& low) : 
+    m_high(high),
+    m_low(low)
+    {}
+    
+    PriorityPointerPair(T_SP& low) : 
+    m_high(),
+    m_low(low)
+    {}
+    
+    void
+    SwapLow(pointer_type l)
+    {
+        m_low.swap(l);
+    }
+    
+    void
+    SwapHigh(pointer_type h)
+    {
+        m_high.swap(h);
+    }
+    
+    void
+    SwapLow(T_SP l)
+    {
+        m_low.swap(l);
+    }
+
+    void
+    SwapHigh(T_SP h)
+    {
+        m_high.swap(h);
+    }
+    
+    T_SP
+    GetLow()
+    {
+        return m_low;
+    }
+    
+    T_SP
+    GetHigh()
+    {
+        return m_high;
+    }
+    
+    T_SP
+    Get()
+    {
+        if (m_high.get())
+            return m_high;
+        return m_low;
+    }
+    
+    void
+    ResetHigh()
+    {
+        m_high.reset();
+    }
+    
+    void
+    ResetLow()
+    {
+        m_low.reset();
+    }
+    
+    void
+    Reset()
+    {
+        ResetLow();
+        ResetHigh();
+    }
+    
+    reference_type
+    operator*() const
+    {
+        return Get().operator*();
+    }
+    
+    pointer_type
+    operator->() const
+    {
+        return Get().operator->();
+    }
+    
+    ~PriorityPointerPair();
+    
+private:
+
+    T_SP m_high;
+    T_SP m_low;
+    
+    DISALLOW_COPY_AND_ASSIGN (PriorityPointerPair);
+        
+};
+
+} // namespace lldb_utility
+
+#endif // #ifndef liblldb_PriorityPointerPair_h_
diff --git a/include/lldb/Utility/RefCounter.h b/include/lldb/Utility/RefCounter.h
index 7c3e341..6daed54 100644
--- a/include/lldb/Utility/RefCounter.h
+++ b/include/lldb/Utility/RefCounter.h
@@ -20,8 +20,6 @@
 // RefCounter ref(ptr);
 // (of course, the pointer is a shared resource, and must be accessible to
 // everyone who needs it). Synchronization is handled by RefCounter itself
-// To check if more than 1 RefCounter is attached to the same value, you can
-// either call shared(), or simply cast ref to bool
 // The counter is decreased each time a RefCounter to it goes out of scope
 //----------------------------------------------------------------------
 class RefCounter
diff --git a/include/lldb/lldb-forward-rtti.h b/include/lldb/lldb-forward-rtti.h
index b5a02d6..858e521 100644
--- a/include/lldb/lldb-forward-rtti.h
+++ b/include/lldb/lldb-forward-rtti.h
@@ -56,11 +56,13 @@
     typedef SharedPtr<lldb_private::RegularExpression>::Type RegularExpressionSP;
     typedef SharedPtr<lldb_private::Section>::Type SectionSP;
     typedef SharedPtr<lldb_private::SearchFilter>::Type SearchFilterSP;
+    typedef SharedPtr<lldb_private::ScriptSummaryFormat>::Type ScriptFormatSP;
     typedef SharedPtr<lldb_private::StackFrame>::Type StackFrameSP;
     typedef SharedPtr<lldb_private::StackFrameList>::Type StackFrameListSP;
     typedef SharedPtr<lldb_private::StopInfo>::Type StopInfoSP;
     typedef SharedPtr<lldb_private::StoppointLocation>::Type StoppointLocationSP;
     typedef SharedPtr<lldb_private::Stream>::Type StreamSP;
+    typedef SharedPtr<lldb_private::StringSummaryFormat>::Type StringSummaryFormatSP;
     typedef SharedPtr<lldb_private::SummaryFormat>::Type SummaryFormatSP;
     typedef SharedPtr<lldb_private::SymbolFile>::Type SymbolFileSP;
     typedef SharedPtr<lldb_private::SymbolContextSpecifier>::Type SymbolContextSpecifierSP;
diff --git a/include/lldb/lldb-forward.h b/include/lldb/lldb-forward.h
index 4b3a97f..9d616d1 100644
--- a/include/lldb/lldb-forward.h
+++ b/include/lldb/lldb-forward.h
@@ -114,6 +114,7 @@
 class   RegisterValue;
 class   RegularExpression;
 class   Scalar;
+class   ScriptSummaryFormat;
 class   ScriptInterpreter;
 class   ScriptInterpreterPython;
 class   SearchFilter;
@@ -131,6 +132,7 @@
 class   StreamFile;
 class   StreamString;
 class   StringList;
+class   StringSummaryFormat;
 class   SummaryFormat;
 class   Symbol;
 class   SymbolContext;
diff --git a/lldb.xcodeproj/project.pbxproj b/lldb.xcodeproj/project.pbxproj
index 41882a2..47345bf 100644
--- a/lldb.xcodeproj/project.pbxproj
+++ b/lldb.xcodeproj/project.pbxproj
@@ -402,6 +402,7 @@
 		4CCA645613B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644813B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp */; };
 		4CCA645813B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644A13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp */; };
 		4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; };
+		94031A9E13CF486700DCFF3C /* InputReaderEZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94031A9D13CF486600DCFF3C /* InputReaderEZ.cpp */; };
 		9415F61813B2C0EF00A52B36 /* FormatManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9415F61713B2C0EF00A52B36 /* FormatManager.cpp */; };
 		94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.cpp */; };
 		9463D4CD13B1798800C230D4 /* CommandObjectType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */; };
@@ -631,8 +632,8 @@
 		261B5A5311C3F2AD00AABD0A /* SharingPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingPtr.h; path = include/lldb/Utility/SharingPtr.h; sourceTree = "<group>"; };
 		26217930133BC8640083B112 /* lldb-private-types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-private-types.h"; path = "include/lldb/lldb-private-types.h"; sourceTree = "<group>"; };
 		26217932133BCB850083B112 /* lldb-private-enumerations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-private-enumerations.h"; path = "include/lldb/lldb-private-enumerations.h"; sourceTree = "<group>"; };
-		263664921140A4930075843B /* Debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Debugger.cpp; path = source/Core/Debugger.cpp; sourceTree = "<group>"; };
-		263664941140A4C10075843B /* Debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Debugger.h; path = include/lldb/Core/Debugger.h; sourceTree = "<group>"; };
+		263664921140A4930075843B /* Debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Debugger.cpp; path = source/Core/Debugger.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+		263664941140A4C10075843B /* Debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Debugger.h; path = include/lldb/Core/Debugger.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		26368A3B126B697600E8659F /* darwin-debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "darwin-debug.cpp"; path = "tools/darwin-debug/darwin-debug.cpp"; sourceTree = "<group>"; };
 		263E949D13661AE400E7D1CE /* UnwindAssembly-x86.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "UnwindAssembly-x86.cpp"; sourceTree = "<group>"; };
 		263E949E13661AE400E7D1CE /* UnwindAssembly-x86.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UnwindAssembly-x86.h"; sourceTree = "<group>"; };
@@ -677,7 +678,7 @@
 		266F5CBB12FC846200DFCE33 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Config.h; path = include/lldb/Host/Config.h; sourceTree = "<group>"; };
 		2671A0CD134825F6003A87BB /* ConnectionMachPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConnectionMachPort.h; path = include/lldb/Core/ConnectionMachPort.h; sourceTree = "<group>"; };
 		2671A0CF13482601003A87BB /* ConnectionMachPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ConnectionMachPort.cpp; path = source/Core/ConnectionMachPort.cpp; sourceTree = "<group>"; };
-		2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; };
+		2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		2672D8471189055500FF4019 /* CommandObjectFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectFrame.h; path = source/Commands/CommandObjectFrame.h; sourceTree = "<group>"; };
 		26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GDBRemoteCommunicationClient.cpp; sourceTree = "<group>"; };
 		26744EEE1338317700EF765A /* GDBRemoteCommunicationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationClient.h; sourceTree = "<group>"; };
@@ -724,7 +725,7 @@
 		26A0604811A5D03C00F75969 /* Baton.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Baton.cpp; path = source/Core/Baton.cpp; sourceTree = "<group>"; };
 		26A3B4AC1181454800381BC2 /* ObjectContainerBSDArchive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectContainerBSDArchive.cpp; sourceTree = "<group>"; };
 		26A3B4AD1181454800381BC2 /* ObjectContainerBSDArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectContainerBSDArchive.h; sourceTree = "<group>"; };
-		26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLDBWrapPython.cpp; path = source/LLDBWrapPython.cpp; sourceTree = "<group>"; };
+		26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = LLDBWrapPython.cpp; path = source/LLDBWrapPython.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		26A7A034135E6E4200FB369E /* NamedOptionValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NamedOptionValue.cpp; path = source/Interpreter/NamedOptionValue.cpp; sourceTree = "<group>"; };
 		26A7A036135E6E5300FB369E /* NamedOptionValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NamedOptionValue.h; path = include/lldb/Interpreter/NamedOptionValue.h; sourceTree = "<group>"; };
 		26B167A41123BF5500DC7B4F /* ThreadSafeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadSafeValue.h; path = include/lldb/Core/ThreadSafeValue.h; sourceTree = "<group>"; };
@@ -830,7 +831,7 @@
 		26BC7D7E10F1B77400F91463 /* Timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Timer.h; path = include/lldb/Core/Timer.h; sourceTree = "<group>"; };
 		26BC7D8010F1B77400F91463 /* UserID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserID.h; path = include/lldb/Core/UserID.h; sourceTree = "<group>"; };
 		26BC7D8110F1B77400F91463 /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Value.h; path = include/lldb/Core/Value.h; sourceTree = "<group>"; };
-		26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = "<group>"; };
+		26BC7D8210F1B77400F91463 /* ValueObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = ValueObject.h; path = include/lldb/Core/ValueObject.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		26BC7D8310F1B77400F91463 /* ValueObjectChild.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectChild.h; path = include/lldb/Core/ValueObjectChild.h; sourceTree = "<group>"; };
 		26BC7D8410F1B77400F91463 /* ValueObjectList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectList.h; path = include/lldb/Core/ValueObjectList.h; sourceTree = "<group>"; };
 		26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectVariable.h; path = include/lldb/Core/ValueObjectVariable.h; sourceTree = "<group>"; };
@@ -928,7 +929,7 @@
 		26BC7E9610F1B85900F91463 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Timer.cpp; path = source/Core/Timer.cpp; sourceTree = "<group>"; };
 		26BC7E9810F1B85900F91463 /* UserID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserID.cpp; path = source/Core/UserID.cpp; sourceTree = "<group>"; };
 		26BC7E9910F1B85900F91463 /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Value.cpp; path = source/Core/Value.cpp; sourceTree = "<group>"; };
-		26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; };
+		26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectChild.cpp; path = source/Core/ValueObjectChild.cpp; sourceTree = "<group>"; };
 		26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectList.cpp; path = source/Core/ValueObjectList.cpp; sourceTree = "<group>"; };
 		26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectVariable.cpp; path = source/Core/ValueObjectVariable.cpp; sourceTree = "<group>"; };
@@ -1019,8 +1020,8 @@
 		26DB3E141379E7AD0080DC73 /* ABISysV_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ABISysV_x86_64.h; sourceTree = "<group>"; };
 		26DC6A101337FE6900FF7998 /* lldb-platform */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "lldb-platform"; sourceTree = BUILT_PRODUCTS_DIR; };
 		26DC6A1C1337FECA00FF7998 /* lldb-platform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lldb-platform.cpp"; path = "tools/lldb-platform/lldb-platform.cpp"; sourceTree = "<group>"; };
-		26DE1E6911616C2E00A093E2 /* lldb-forward-rtti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-forward-rtti.h"; path = "include/lldb/lldb-forward-rtti.h"; sourceTree = "<group>"; };
-		26DE1E6A11616C2E00A093E2 /* lldb-forward.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-forward.h"; path = "include/lldb/lldb-forward.h"; sourceTree = "<group>"; };
+		26DE1E6911616C2E00A093E2 /* lldb-forward-rtti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = "lldb-forward-rtti.h"; path = "include/lldb/lldb-forward-rtti.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+		26DE1E6A11616C2E00A093E2 /* lldb-forward.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = "lldb-forward.h"; path = "include/lldb/lldb-forward.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		26DE204011618AB900A093E2 /* SBSymbolContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBSymbolContext.h; path = include/lldb/API/SBSymbolContext.h; sourceTree = "<group>"; };
 		26DE204211618ACA00A093E2 /* SBAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBAddress.h; path = include/lldb/API/SBAddress.h; sourceTree = "<group>"; };
 		26DE204411618ADA00A093E2 /* SBAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBAddress.cpp; path = source/API/SBAddress.cpp; sourceTree = "<group>"; };
@@ -1169,11 +1170,14 @@
 		69A01E1E1236C5D400C660B5 /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mutex.cpp; sourceTree = "<group>"; };
 		69A01E1F1236C5D400C660B5 /* Symbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Symbols.cpp; sourceTree = "<group>"; };
 		69A01E201236C5D400C660B5 /* TimeValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeValue.cpp; sourceTree = "<group>"; };
-		9415F61613B2C0DC00A52B36 /* FormatManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FormatManager.h; path = include/lldb/Core/FormatManager.h; sourceTree = "<group>"; };
-		9415F61713B2C0EF00A52B36 /* FormatManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatManager.cpp; path = source/Core/FormatManager.cpp; sourceTree = "<group>"; };
+		94031A9B13CF484600DCFF3C /* InputReaderEZ.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = InputReaderEZ.h; path = include/lldb/Core/InputReaderEZ.h; sourceTree = "<group>"; };
+		94031A9D13CF486600DCFF3C /* InputReaderEZ.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InputReaderEZ.cpp; path = source/Core/InputReaderEZ.cpp; sourceTree = "<group>"; };
+		94031A9F13CF5B3D00DCFF3C /* PriorityPointerPair.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PriorityPointerPair.h; path = include/lldb/Utility/PriorityPointerPair.h; sourceTree = "<group>"; };
+		9415F61613B2C0DC00A52B36 /* FormatManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = FormatManager.h; path = include/lldb/Core/FormatManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+		9415F61713B2C0EF00A52B36 /* FormatManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = FormatManager.cpp; path = source/Core/FormatManager.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		94611EAF13CCA363003A22AF /* RefCounter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RefCounter.h; path = include/lldb/Utility/RefCounter.h; sourceTree = "<group>"; };
 		94611EB113CCA4A4003A22AF /* RefCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RefCounter.cpp; path = source/Utility/RefCounter.cpp; sourceTree = "<group>"; };
-		9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectType.cpp; path = source/Commands/CommandObjectType.cpp; sourceTree = "<group>"; };
+		9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = CommandObjectType.cpp; path = source/Commands/CommandObjectType.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		9463D4CE13B179A500C230D4 /* CommandObjectType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandObjectType.h; path = source/Commands/CommandObjectType.h; sourceTree = "<group>"; };
 		9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeHierarchyNavigator.cpp; path = source/Symbol/TypeHierarchyNavigator.cpp; sourceTree = "<group>"; };
 		9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeHierarchyNavigator.h; path = include/lldb/Symbol/TypeHierarchyNavigator.h; sourceTree = "<group>"; };
@@ -1797,6 +1801,7 @@
 				2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */,
 				2682F16B115EDA0D00CCFF99 /* PseudoTerminal.h */,
 				2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */,
+				94031A9F13CF5B3D00DCFF3C /* PriorityPointerPair.h */,
 			);
 			name = Utility;
 			sourceTree = "<group>";
@@ -1929,6 +1934,8 @@
 				26F73061139D8FDB00FD51C7 /* History.cpp */,
 				9AA69DBB118A029E00D753A0 /* InputReader.h */,
 				9AA69DB5118A027A00D753A0 /* InputReader.cpp */,
+				94031A9B13CF484600DCFF3C /* InputReaderEZ.h */,
+				94031A9D13CF486600DCFF3C /* InputReaderEZ.cpp */,
 				9A9E1F0013980943005AC039 /* InputReaderStack.h */,
 				9A9E1EFE1398086D005AC039 /* InputReaderStack.cpp */,
 				26BC7D6510F1B77400F91463 /* IOStreamMacros.h */,
@@ -3271,6 +3278,7 @@
 				26ED3D6D13C563810017D45E /* OptionGroupVariable.cpp in Sources */,
 				26F4214413C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp in Sources */,
 				94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */,
+				94031A9E13CF486700DCFF3C /* InputReaderEZ.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/scripts/lldb.swig b/scripts/lldb.swig
index 9d9cc25..158004c 100644
--- a/scripts/lldb.swig
+++ b/scripts/lldb.swig
@@ -359,4 +359,128 @@
     return stop_at_breakpoint;
 }
 
+SWIGEXPORT std::string
+LLDBSwigPythonCallTypeScript 
+(
+    const char *python_function_name,
+    const char *session_dictionary_name,
+    const lldb::ValueObjectSP& valobj_sp
+)
+{
+    lldb::SBValue sb_value (valobj_sp);
+
+    std::string retval = "";
+
+    PyObject *ValObj_PyObj = SWIG_NewPointerObj((void *) &valobj_sp, SWIGTYPE_p_lldb__SBValue, 0);
+    
+    if (ValObj_PyObj == NULL)
+        return retval;
+        
+    if (!python_function_name || !session_dictionary_name)
+        return retval;
+
+    PyObject *pmodule, *main_dict, *session_dict, *pfunc;
+    PyObject *pargs, *pvalue;
+    
+    pmodule = PyImport_AddModule ("__main__");
+    if (pmodule != NULL)
+    {
+        main_dict = PyModule_GetDict (pmodule);
+        if (main_dict != NULL)
+        {
+            PyObject *key, *value;
+            Py_ssize_t pos = 0;
+             
+            // Find the current session's dictionary in the main module's dictionary.
+
+            if (PyDict_Check (main_dict))
+             
+            {
+                session_dict = NULL;   
+                while (PyDict_Next (main_dict, &pos, &key, &value))
+                {
+                    // We have stolen references to the key and value objects in the dictionary; we need to increment 
+                    // them now so that Python's garbage collector doesn't collect them out from under us.
+                    Py_INCREF (key);
+                    Py_INCREF (value);
+                    if (strcmp (PyString_AsString (key), session_dictionary_name) == 0)
+                    {
+                        session_dict = value;
+                        break;
+                    }
+                }
+            }
+            
+            if (!session_dict || !PyDict_Check (session_dict))
+                return retval;
+                
+            // Find the function we need to call in the current session's dictionary.
+
+            pos = 0;
+            pfunc = NULL;
+            while (PyDict_Next (session_dict, &pos, &key, &value))
+            {
+                if (PyString_Check (key))
+                {
+                    // We have stolen references to the key and value objects in the dictionary; we need to increment 
+                    // them now so that Python's garbage collector doesn't collect them out from under us.
+                    Py_INCREF (key);
+                    Py_INCREF (value);
+                    if (strcmp (PyString_AsString (key), python_function_name) == 0)
+                    {
+                        pfunc = value;
+                        break;
+                    }
+                }
+            }
+
+            // Set up the arguments and call the function.
+                
+            if (pfunc && PyCallable_Check (pfunc))
+            {
+                pargs = PyTuple_New (2);
+                if (pargs == NULL)
+                {
+                    if (PyErr_Occurred())
+                        PyErr_Clear();
+                    return retval;
+                }
+                
+                PyTuple_SetItem (pargs, 0, ValObj_PyObj);  // This "steals" a reference to ValObj_PyObj
+                PyTuple_SetItem (pargs, 1, session_dict); // This "steals" a reference to session_dict
+                pvalue = PyObject_CallObject (pfunc, pargs);
+                Py_DECREF (pargs);
+                
+                if (pvalue != NULL)
+                {
+                    if (pvalue != Py_None)
+                        retval = std::string(PyString_AsString(pvalue));
+                    else
+                        retval = "None";
+                    Py_DECREF (pvalue);
+                }
+                else if (PyErr_Occurred ())
+                {
+                    PyErr_Clear();
+                }
+                Py_INCREF (session_dict);
+            }
+            else if (PyErr_Occurred())
+            {
+                PyErr_Clear();
+            }
+        }
+        else if (PyErr_Occurred())
+        {
+            PyErr_Clear();
+        }
+    }
+    else if (PyErr_Occurred ())
+    {
+        PyErr_Clear ();
+    }
+    return retval;
+}
+
+
 %}
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
index 0f1914b..97b9314 100644
--- a/source/API/SBCommandInterpreter.cpp
+++ b/source/API/SBCommandInterpreter.cpp
@@ -314,6 +314,15 @@
     const lldb::BreakpointLocationSP& sb_bp_loc
 );
 
+extern "C" std::string
+LLDBSwigPythonCallTypeScript 
+(
+    const char *python_function_name,
+    const char *session_dictionary_name,
+    const lldb::ValueObjectSP& valobj_sp
+);
+
+
 extern "C" void init_lldb(void);
 
 void
@@ -324,6 +333,7 @@
     {
         g_initialized = true;
         ScriptInterpreter::InitializeInterpreter (init_lldb, 
-                                                  LLDBSwigPythonBreakpointCallbackFunction);
+                                                  LLDBSwigPythonBreakpointCallbackFunction,
+                                                  LLDBSwigPythonCallTypeScript);
     }
 }
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index e51919c..aeabb17 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -472,6 +472,28 @@
     return sb_value;
 }
 
+lldb::SBValue
+SBValue::GetValueForExpressionPath(const char* expr_path)
+{
+    lldb::ValueObjectSP child_sp;
+    if (m_opaque_sp)
+    {
+        if (m_opaque_sp->GetUpdatePoint().GetTarget())
+        {
+            Mutex::Locker api_locker (m_opaque_sp->GetUpdatePoint().GetTarget()->GetAPIMutex());
+            // using default values for all the fancy options, just do it if you can
+            child_sp = m_opaque_sp->GetValueForExpressionPath(expr_path);
+        }
+    }
+    
+    SBValue sb_value (child_sp);
+    
+    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+    if (log)
+        log->Printf ("SBValue(%p)::GetValueForExpressionPath (expr_path=\"%s\") => SBValue(%p)", m_opaque_sp.get(), expr_path, sb_value.get());
+    
+    return sb_value;
+}
 
 uint32_t
 SBValue::GetNumChildren ()
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
index c0ffddb..b1e7c12 100644
--- a/source/Commands/CommandObjectType.cpp
+++ b/source/Commands/CommandObjectType.cpp
@@ -15,8 +15,10 @@
 #include "lldb/Core/ConstString.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/FormatManager.h"
+#include "lldb/Core/InputReaderEZ.h"
 #include "lldb/Core/RegularExpression.h"
 #include "lldb/Core/State.h"
+#include "lldb/Core/StringList.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandObject.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
@@ -416,6 +418,162 @@
 // CommandObjectTypeSummaryAdd
 //-------------------------------------------------------------------------
 
+class ScriptAddOptions
+{
+    
+public:
+    
+    bool m_skip_pointers;
+    bool m_skip_references;
+    bool m_cascade;
+    bool m_callback_is_synchronous;
+    StringList m_target_types;
+    StringList m_user_source;
+    
+    ScriptAddOptions(bool p,
+                     bool r,
+                     bool c) :
+    m_skip_pointers(p),
+    m_skip_references(r),
+    m_cascade(c),
+    m_target_types(),
+    m_user_source()
+    {
+    }
+    
+    typedef lldb::SharedPtr<ScriptAddOptions>::Type SharedPointer;
+    
+};
+
+static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.";
+
+class TypeScriptAddInputReader : public InputReaderEZ
+{
+private:
+    DISALLOW_COPY_AND_ASSIGN (TypeScriptAddInputReader);
+public:
+    TypeScriptAddInputReader(Debugger& debugger) : 
+    InputReaderEZ(debugger)
+    {}
+    
+    virtual
+    ~TypeScriptAddInputReader()
+    {
+    }
+    
+    virtual void ActivateHandler(HandlerData& data)
+    {
+        StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+        bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+        if (!batch_mode)
+        {
+            out_stream->Printf ("%s\n", g_reader_instructions);
+            if (data.reader.GetPrompt())
+                out_stream->Printf ("%s", data.reader.GetPrompt());
+            out_stream->Flush();
+        }
+    }
+    
+    virtual void ReactivateHandler(HandlerData& data)
+    {
+        StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+        bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+        if (data.reader.GetPrompt() && !batch_mode)
+        {
+            out_stream->Printf ("%s", data.reader.GetPrompt());
+            out_stream->Flush();
+        }
+    }
+    virtual void GotTokenHandler(HandlerData& data)
+    {
+        StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+        bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+        if (data.bytes && data.bytes_len && data.baton)
+        {
+            ((ScriptAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len);
+        }
+        if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
+        {
+            out_stream->Printf ("%s", data.reader.GetPrompt());
+            out_stream->Flush();
+        }
+    }
+    virtual void InterruptHandler(HandlerData& data)
+    {
+        StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+        bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+        data.reader.SetIsDone (true);
+        if (!batch_mode)
+        {
+            out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+            out_stream->Flush();
+        }
+    }
+    virtual void EOFHandler(HandlerData& data)
+    {
+        data.reader.SetIsDone (true);
+    }
+    virtual void DoneHandler(HandlerData& data)
+    {
+        StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+        ScriptAddOptions *options_ptr = ((ScriptAddOptions*)data.baton);
+        if (!options_ptr)
+        {
+            out_stream->Printf ("Internal error #1: no script attached.\n");
+            out_stream->Flush();
+            return;
+        }
+        
+        ScriptAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope
+        
+        ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+        if (!interpreter)
+        {
+            out_stream->Printf ("Internal error #2: no script attached.\n");
+            out_stream->Flush();
+            return;
+        }
+        StringList funct_name_sl;
+        if (!interpreter->GenerateTypeScriptFunction (options->m_user_source, 
+                                                      funct_name_sl))
+        {
+            out_stream->Printf ("Internal error #3: no script attached.\n");
+            out_stream->Flush();
+            return;
+        }
+        if (funct_name_sl.GetSize() == 0)
+        {
+            out_stream->Printf ("Internal error #4: no script attached.\n");
+            out_stream->Flush();
+            return;
+        }
+        const char *funct_name = funct_name_sl.GetStringAtIndex(0);
+        if (!funct_name || !funct_name[0])
+        {
+            out_stream->Printf ("Internal error #5: no script attached.\n");
+            out_stream->Flush();
+            return;
+        }
+        // now I have a valid function name, let's add this as script for every type in the list
+        
+        SummaryFormatSP script_format;
+        script_format.reset(new ScriptSummaryFormat(options->m_cascade,
+                                                    options->m_skip_pointers,
+                                                    options->m_skip_references,
+                                                    true,
+                                                    true,
+                                                    false,
+                                                    std::string(funct_name),
+                                                    options->m_user_source.CopyList("     ")));
+        
+        for (int i = 0; i < options->m_target_types.GetSize(); i++)
+        {
+            const char *type_name = options->m_target_types.GetStringAtIndex(i);
+            Debugger::SummaryFormats::Add(ConstString(type_name), script_format);
+        }
+    }
+};
+
 class CommandObjectTypeSummaryAdd : public CommandObject
 {
     
@@ -471,6 +629,17 @@
                 case 'n':
                     m_name = new ConstString(option_arg);
                     break;
+                case 's':
+                    m_python_script = std::string(option_arg);
+                    m_is_add_script = true;
+                    break;
+                case 'F':
+                    m_python_function = std::string(option_arg);
+                    m_is_add_script = true;
+                    break;
+                case 'P':
+                    m_is_add_script = true;
+                    break;
                 default:
                     error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
                     break;
@@ -490,6 +659,9 @@
             m_skip_pointers = false;
             m_regex = false;
             m_name = NULL;
+            m_python_script = "";
+            m_python_function = "";
+            m_is_add_script = false;
         }
         
         const OptionDefinition*
@@ -513,6 +685,9 @@
         bool m_regex;
         std::string m_format_string;
         ConstString* m_name;
+        std::string m_python_script;
+        std::string m_python_function;
+        bool m_is_add_script;
     };
     
     CommandOptions m_options;
@@ -601,9 +776,170 @@
     {
     }
     
+    void
+    CollectPythonScript
+    (
+     ScriptAddOptions *options,
+     CommandReturnObject &result
+     )
+    {
+        InputReaderSP reader_sp (new TypeScriptAddInputReader(m_interpreter.GetDebugger()));
+        if (reader_sp && options)
+        {
+            
+            Error err (reader_sp->Initialize (options));
+            if (err.Success())
+            {
+                m_interpreter.GetDebugger().PushInputReader (reader_sp);
+                result.SetStatus (eReturnStatusSuccessFinishNoResult);
+            }
+            else
+            {
+                result.AppendError (err.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+        }
+        else
+        {
+            result.AppendError("out of memory");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        
+    }
+
     bool
     Execute (Args& command, CommandReturnObject &result)
     {
+        if (m_options.m_is_add_script)
+            return Execute_ScriptSummary(command, result);
+        else
+            return Execute_StringSummary(command, result);
+    }
+    
+    bool
+    Execute_ScriptSummary (Args& command, CommandReturnObject &result)
+    {
+        const size_t argc = command.GetArgumentCount();
+        
+        if (argc < 1)
+        {
+            result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        
+        if (!m_options.m_python_function.empty()) // we have a Python function ready to use
+        {
+            ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+            if (!interpreter)
+            {
+                result.AppendError ("Internal error #1N: no script attached.\n");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+            const char *funct_name = m_options.m_python_function.c_str();
+            if (!funct_name || !funct_name[0])
+            {
+                result.AppendError ("Internal error #2N: no script attached.\n");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+            // now I have a valid function name, let's add this as script for every type in the list
+            
+            SummaryFormatSP script_format;
+            script_format.reset(new ScriptSummaryFormat(m_options.m_cascade,
+                                                        m_options.m_skip_pointers,
+                                                        m_options.m_skip_references,
+                                                        true,
+                                                        true,
+                                                        false,
+                                                        std::string(funct_name),
+                                                        "     " + m_options.m_python_function + "(valobj,dict)"));
+            
+            for (int i = 0; i < command.GetArgumentCount(); i++)
+            {
+                const char *type_name = command.GetArgumentAtIndex(i);
+                Debugger::SummaryFormats::Add(ConstString(type_name), script_format);
+            }
+        }
+        else if (m_options.m_python_script.empty()) // use an InputReader to grab Python code from the user
+        {        
+            ScriptAddOptions *options = new ScriptAddOptions(m_options.m_skip_pointers,
+                                                             m_options.m_skip_references,
+                                                             m_options.m_cascade);
+            
+            for(int i = 0; i < argc; i++) {
+                const char* typeA = command.GetArgumentAtIndex(i);
+                if (typeA && *typeA)
+                    options->m_target_types << typeA;
+                else
+                {
+                    result.AppendError("empty typenames not allowed");
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+            }
+            
+            CollectPythonScript(options,result);
+            return result.Succeeded();
+        }
+        else // we have a quick 1-line script, just use it
+        {
+            ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+            if (!interpreter)
+            {
+                result.AppendError ("Internal error #1Q: no script attached.\n");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+            StringList funct_sl;
+            funct_sl << m_options.m_python_script.c_str();
+            StringList funct_name_sl;
+            if (!interpreter->GenerateTypeScriptFunction (funct_sl, 
+                                                          funct_name_sl))
+            {
+                result.AppendError ("Internal error #2Q: no script attached.\n");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+            if (funct_name_sl.GetSize() == 0)
+            {
+                result.AppendError ("Internal error #3Q: no script attached.\n");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+            const char *funct_name = funct_name_sl.GetStringAtIndex(0);
+            if (!funct_name || !funct_name[0])
+            {
+                result.AppendError ("Internal error #4Q: no script attached.\n");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+            // now I have a valid function name, let's add this as script for every type in the list
+            
+            ScriptFormatSP script_format;
+            script_format.reset(new ScriptSummaryFormat(m_options.m_cascade,
+                                                        m_options.m_skip_pointers,
+                                                        m_options.m_skip_references,
+                                                        true,
+                                                        true,
+                                                        false,
+                                                        std::string(funct_name),
+                                                        "     " + m_options.m_python_script));
+            
+            for (int i = 0; i < command.GetArgumentCount(); i++)
+            {
+                const char *type_name = command.GetArgumentAtIndex(i);
+                Debugger::SummaryFormats::Add(ConstString(type_name), script_format);
+            }
+        }
+        
+        return result.Succeeded();
+    }
+
+    bool
+    Execute_StringSummary (Args& command, CommandReturnObject &result)
+    {
         const size_t argc = command.GetArgumentCount();
         
         if (argc < 1 && !m_options.m_name)
@@ -624,11 +960,13 @@
         
         Error error;
         
-        SummaryFormat::SharedPointer entry(new SummaryFormat(format_cstr,m_options.m_cascade,
-                                             m_options.m_no_children,m_options.m_no_value,
-                                             m_options.m_one_liner,
-                                             m_options.m_skip_pointers,
-                                             m_options.m_skip_references));
+        SummaryFormat::SharedPointer entry(new StringSummaryFormat(m_options.m_cascade,
+                                                                       m_options.m_skip_pointers,
+                                                                       m_options.m_skip_references,
+                                                                       m_options.m_no_children,
+                                                                       m_options.m_no_value,
+                                                                       m_options.m_one_liner,
+                                                                       format_cstr));
         
         if (error.Fail()) 
         {
@@ -698,6 +1036,9 @@
     { LLDB_OPT_SET_2  , true, "format-string", 'f', required_argument, NULL, 0, eArgTypeSummaryString,    "Format string used to display text and object contents."},
     { LLDB_OPT_SET_2,   false, "expand", 'e', no_argument, NULL, 0, eArgTypeBoolean,    "Expand aggregate data types to show children on separate lines."},
     { LLDB_OPT_SET_2,   false, "name", 'n', required_argument, NULL, 0, eArgTypeName,    "A name for this summary string."},
+    { LLDB_OPT_SET_3, false, "python-script", 's', required_argument, NULL, 0, eArgTypeName, "Give a one-liner Python script as part of the command."},
+    { LLDB_OPT_SET_3, false, "python-function", 'F', required_argument, NULL, 0, eArgTypeName, "Give the name of a Python function to use for this type."},
+    { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeName, "Input Python code to use for this type manually."},
     { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
 };
 
@@ -808,8 +1149,8 @@
 // CommandObjectTypeSummaryList
 //-------------------------------------------------------------------------
 
-bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
-bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry);
+bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const StringSummaryFormat::SharedPointer& entry);
+bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const StringSummaryFormat::SharedPointer& entry);
 
 class CommandObjectTypeSummaryList;
 
@@ -912,16 +1253,7 @@
                   CommandReturnObject *result)
     {
         if (regex == NULL || regex->Execute(type)) 
-        {
-                result->GetOutputStream().Printf ("%s: `%s`%s%s%s%s%s%s\n", type, 
-                                                  entry->m_format.c_str(),
-                                                  entry->m_cascades ? "" : " (not cascading)",
-                                                  entry->m_dont_show_children ? "" : " (show children)",
-                                                  entry->m_dont_show_value ? " (hide value)" : "",
-                                                  entry->m_show_members_oneliner ? " (one-line printout)" : "",
-                                                  entry->m_skip_pointers ? " (skip pointers)" : "",
-                                                  entry->m_skip_references ? " (skip references)" : "");
-        }
+                result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
         return true;
     }
     
@@ -951,8 +1283,6 @@
 }
 
 
-
-
 class CommandObjectTypeFormat : public CommandObjectMultiword
 {
 public:
@@ -983,10 +1313,10 @@
                             "A set of commands for editing variable summary display options",
                             "type summary [<sub-command-options>] ")
     {
-        LoadSubCommand ("add",    CommandObjectSP (new CommandObjectTypeSummaryAdd (interpreter)));
-        LoadSubCommand ("clear",  CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter)));
-        LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter)));
-        LoadSubCommand ("list",   CommandObjectSP (new CommandObjectTypeSummaryList (interpreter)));
+        LoadSubCommand ("add",           CommandObjectSP (new CommandObjectTypeSummaryAdd (interpreter)));
+        LoadSubCommand ("clear",         CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter)));
+        LoadSubCommand ("delete",        CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter)));
+        LoadSubCommand ("list",          CommandObjectSP (new CommandObjectTypeSummaryList (interpreter)));
     }
     
     
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index 2c36dbb..029a1d8 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -733,6 +733,8 @@
             // if this is a V, print the value using the default format
             if (*format_name == 'V')
                 *val_obj_display = ValueObject::eDisplayValue;
+            if (*format_name == 'L')
+                *val_obj_display = ValueObject::eDisplayLocation;
         }
         // a good custom format tells us to print the value using it
         else
diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp
index 6e21fe7..61faca4 100644
--- a/source/Core/Error.cpp
+++ b/source/Core/Error.cpp
@@ -51,6 +51,14 @@
 {
 }
 
+Error::Error (const char* err_str):
+    m_code (0),
+    m_type (eErrorTypeInvalid),
+    m_string ()
+{
+    SetErrorString(err_str);
+}
+
 //----------------------------------------------------------------------
 // Assignment operator
 //----------------------------------------------------------------------
diff --git a/source/Core/FormatManager.cpp b/source/Core/FormatManager.cpp
index 040b9cd..7be3791 100644
--- a/source/Core/FormatManager.cpp
+++ b/source/Core/FormatManager.cpp
@@ -14,6 +14,8 @@
 // Other libraries and framework includes
 // Project includes
 
+#include "lldb/Core/Debugger.h"
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -217,3 +219,54 @@
             return lldb::eFormatInvalid;
     }
 }
+
+std::string
+StringSummaryFormat::FormatObject(lldb::ValueObjectSP object)
+{
+    if (!object.get())
+        return "NULL";
+    
+    StreamString s;
+    ExecutionContext exe_ctx;
+    object->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
+    SymbolContext sc;
+    if (exe_ctx.frame)
+        sc = exe_ctx.frame->GetSymbolContext(lldb::eSymbolContextEverything);
+    
+    if (m_show_members_oneliner)
+    {
+        const uint32_t num_children = object->GetNumChildren();
+        if (num_children)
+        {
+            s.PutChar('(');
+            
+            for (uint32_t idx=0; idx<num_children; ++idx)
+            {
+                lldb::ValueObjectSP child_sp(object->GetChildAtIndex(idx, true));
+                if (child_sp.get())
+                {
+                    if (idx)
+                        s.PutCString(", ");
+                    s.PutCString(child_sp.get()->GetName().AsCString());
+                    s.PutChar('=');
+                    s.PutCString(child_sp.get()->GetPrintableRepresentation());
+                }
+            }
+            
+            s.PutChar(')');
+            
+            return s.GetString();
+        }
+        else
+            return "";
+        
+    }
+    else
+    {
+        if (Debugger::FormatPrompt(m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, object.get()))
+            return s.GetString();
+        else
+            return "";
+    }
+}
+
diff --git a/source/Core/InputReader.cpp b/source/Core/InputReader.cpp
index c6e90eb..84cd0a1 100644
--- a/source/Core/InputReader.cpp
+++ b/source/Core/InputReader.cpp
@@ -370,3 +370,14 @@
     return unknown_state_string;
 }
 
+bool
+InputReader::HandlerData::GetBatchMode()
+{
+    return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+}
+
+lldb::StreamSP
+InputReader::HandlerData::GetOutStream()
+{
+    return reader.GetDebugger().GetAsyncOutputStream();
+}
\ No newline at end of file
diff --git a/source/Core/InputReaderEZ.cpp b/source/Core/InputReaderEZ.cpp
new file mode 100644
index 0000000..839d744
--- /dev/null
+++ b/source/Core/InputReaderEZ.cpp
@@ -0,0 +1,80 @@
+//===-- InputReaderEZ.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string>
+
+#include "lldb/Core/InputReaderEZ.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t
+InputReaderEZ::Callback_Impl(void *baton, 
+                             InputReader &reader, 
+                             lldb::InputReaderAction notification,
+                             const char *bytes, 
+                             size_t bytes_len)
+
+{
+    HandlerData hand_data(reader,
+                          bytes,
+                          bytes_len,
+                          baton);
+    
+    switch (notification)
+    {
+        case eInputReaderActivate:
+            reader.ActivateHandler(hand_data);
+            break;
+        case eInputReaderDeactivate:
+            reader.DeactivateHandler(hand_data);
+            break;
+        case eInputReaderReactivate:
+            reader.ReactivateHandler(hand_data);
+            break;
+        case eInputReaderAsynchronousOutputWritten:
+            reader.AsynchronousOutputWrittenHandler(hand_data);
+            break;
+        case eInputReaderGotToken:
+            reader.GotTokenHandler(hand_data);
+            break;
+        case eInputReaderInterrupt:
+            reader.InterruptHandler(hand_data);
+            break;
+        case eInputReaderEndOfFile:
+            reader.EOFHandler(hand_data);
+            break;
+        case eInputReaderDone:
+            reader.DoneHandler(hand_data);
+            break;
+    }
+    return bytes_len;
+}
+
+Error
+InputReaderEZ::Initialize(void* baton,
+                          lldb::InputReaderGranularity token_size,
+                          const char* end_token,
+                          const char *prompt,
+                          bool echo)
+{
+    return InputReader::Initialize(Callback_Impl,
+                                   baton,
+                                   token_size,
+                                   end_token,
+                                   prompt,
+                                   echo);
+}
+
+InputReaderEZ::~InputReaderEZ ()
+{
+}
\ No newline at end of file
diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp
index d339262..fbe0cfe 100644
--- a/source/Core/StringList.cpp
+++ b/source/Core/StringList.cpp
@@ -8,6 +8,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Core/StringList.h"
+
+#include "lldb/Core/StreamString.h"
 #include "lldb/Host/FileSpec.h"
 
 #include <string>
@@ -205,3 +207,33 @@
             idx++;
     }
 }
+
+std::string
+StringList::CopyList(const char* item_preamble,
+                     const char* items_sep)
+{
+    StreamString strm;
+    for (int i = 0; i < GetSize(); i++)
+    {
+        if (i && items_sep && items_sep[0])
+            strm << items_sep;
+        if (item_preamble)
+            strm << item_preamble;
+        strm << GetStringAtIndex(i);
+    }
+    return std::string(strm.GetData());
+}
+
+StringList&
+StringList::operator << (const char* str)
+{
+    AppendString(str);
+    return *this;
+}
+
+StringList&
+StringList::operator << (StringList strings)
+{
+    AppendList(strings);
+    return *this;
+}
\ No newline at end of file
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index d8e0e0f..ca0b0ac 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -29,6 +29,8 @@
 
 #include "lldb/Host/Endian.h"
 
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
 #include "lldb/Symbol/ClangASTType.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/Type.h"
@@ -79,8 +81,8 @@
     m_is_array_item_for_pointer(false),
     m_is_bitfield_for_scalar(false),
     m_last_format_mgr_revision(0),
-    m_last_summary_format(),
     m_last_value_format(),
+    m_last_summary_format(),
     m_forced_summary_format(),
     m_dump_printable_counter(0)
 {
@@ -118,8 +120,8 @@
     m_is_array_item_for_pointer(false),
     m_is_bitfield_for_scalar(false),
     m_last_format_mgr_revision(0),
-    m_last_summary_format(),
     m_last_value_format(),
+    m_last_summary_format(),
     m_forced_summary_format(),
     m_dump_printable_counter(0)
 {
@@ -164,10 +166,9 @@
             m_old_value_str.swap (m_value_str);
             m_value_str.clear();
         }
-        m_location_str.clear();
-        m_summary_str.clear();
-        m_object_desc_str.clear();
 
+        ClearUserVisibleData();
+        
         const bool value_was_valid = GetValueIsValid();
         SetValueDidChange (false);
 
@@ -204,15 +205,15 @@
     if (m_last_format_mgr_revision != Debugger::ValueFormats::GetCurrentRevision())
     {
         if (m_last_summary_format.get())
-            m_last_summary_format.reset((SummaryFormat*)NULL);
+            m_last_summary_format.reset((StringSummaryFormat*)NULL);
         if (m_last_value_format.get())
             m_last_value_format.reset((ValueFormat*)NULL);
         Debugger::ValueFormats::Get(*this, m_last_value_format);
         if (!Debugger::SummaryFormats::Get(*this, m_last_summary_format))
             Debugger::RegexSummaryFormats::Get(*this, m_last_summary_format);
         m_last_format_mgr_revision = Debugger::ValueFormats::GetCurrentRevision();
-        m_value_str.clear();
-        m_summary_str.clear();
+
+        ClearUserVisibleData();
     }
 }
 
@@ -507,221 +508,177 @@
     {        
         if (m_summary_str.empty())
         {
-            SummaryFormat* summary_format = GetSummaryFormat().get();
+            SummaryFormat *summary_format = GetSummaryFormat().get();
 
             if (summary_format)
             {
-                StreamString s;
-                ExecutionContext exe_ctx;
-                this->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
-                SymbolContext sc;
-                if (exe_ctx.frame)
-                    sc = exe_ctx.frame->GetSymbolContext(eSymbolContextEverything);
-                
-                if (summary_format->m_show_members_oneliner)
-                {
-                    const uint32_t num_children = GetNumChildren();
-                    if (num_children)
-                    {
-                        
-                        s.PutChar('(');
-                        
-                        for (uint32_t idx=0; idx<num_children; ++idx)
-                        {
-                            ValueObjectSP child_sp(GetChildAtIndex(idx, true));
-                            if (child_sp.get())
-                            {
-                                if (idx)
-                                    s.PutCString(", ");
-                                s.PutCString(child_sp.get()->GetName().AsCString());
-                                s.PutChar('=');
-                                s.PutCString(child_sp.get()->GetPrintableRepresentation());
-                            }
-                        }
-                        
-                        s.PutChar(')');
-                        
-                        m_summary_str.swap(s.GetString());
-                        return m_summary_str.c_str();
-                    }
-                    else
-                        return "()";
-
-                }
-                else
-                {
-                    if (Debugger::FormatPrompt(summary_format->m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, this))
-                    {
-                        m_summary_str.swap(s.GetString());
-                        return m_summary_str.c_str();
-                    }
-                    else
-                        return NULL;
-                }
+                m_summary_str = summary_format->FormatObject(GetSP());
             }
-            
-            clang_type_t clang_type = GetClangType();
-
-            // See if this is a pointer to a C string?
-            if (clang_type)
+            else
             {
-                StreamString sstr;
-                clang_type_t elem_or_pointee_clang_type;
-                const Flags type_flags (ClangASTContext::GetTypeInfo (clang_type, 
-                                                                      GetClangAST(), 
-                                                                      &elem_or_pointee_clang_type));
+                clang_type_t clang_type = GetClangType();
 
-                ExecutionContextScope *exe_scope = GetExecutionContextScope();
-                if (exe_scope)
+                // See if this is a pointer to a C string?
+                if (clang_type)
                 {
-                    if (type_flags.AnySet (ClangASTContext::eTypeIsArray | ClangASTContext::eTypeIsPointer) &&
-                        ClangASTContext::IsCharType (elem_or_pointee_clang_type))
-                    {
-                        Target *target = exe_scope->CalculateTarget();
-                        if (target != NULL)
-                        {
-                            lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS;
-                            AddressType cstr_address_type = eAddressTypeInvalid;
+                    StreamString sstr;
+                    clang_type_t elem_or_pointee_clang_type;
+                    const Flags type_flags (ClangASTContext::GetTypeInfo (clang_type, 
+                                                                          GetClangAST(), 
+                                                                          &elem_or_pointee_clang_type));
 
-                            size_t cstr_len = 0;
-                            bool capped_data = false;
-                            if (type_flags.Test (ClangASTContext::eTypeIsArray))
+                    ExecutionContextScope *exe_scope = GetExecutionContextScope();
+                    if (exe_scope)
+                    {
+                        if (type_flags.AnySet (ClangASTContext::eTypeIsArray | ClangASTContext::eTypeIsPointer) &&
+                            ClangASTContext::IsCharType (elem_or_pointee_clang_type))
+                        {
+                            Target *target = exe_scope->CalculateTarget();
+                            if (target != NULL)
                             {
-                                // We have an array
-                                cstr_len = ClangASTContext::GetArraySize (clang_type);
-                                if (cstr_len > 512) // TODO: make cap a setting
+                                lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS;
+                                AddressType cstr_address_type = eAddressTypeInvalid;
+
+                                size_t cstr_len = 0;
+                                bool capped_data = false;
+                                if (type_flags.Test (ClangASTContext::eTypeIsArray))
                                 {
+                                    // We have an array
                                     cstr_len = ClangASTContext::GetArraySize (clang_type);
                                     if (cstr_len > 512) // TODO: make cap a setting
                                     {
-                                        capped_data = true;
-                                        cstr_len = 512;
+                                        cstr_len = ClangASTContext::GetArraySize (clang_type);
+                                        if (cstr_len > 512) // TODO: make cap a setting
+                                        {
+                                            capped_data = true;
+                                            cstr_len = 512;
+                                        }
                                     }
-                                }
-                                cstr_address = GetAddressOf (cstr_address_type, true);
-                            }
-                            else
-                            {
-                                // We have a pointer
-                                cstr_address = GetPointerValue (cstr_address_type, true);
-                            }
-                            if (cstr_address != LLDB_INVALID_ADDRESS)
-                            {
-                                Address cstr_so_addr (NULL, cstr_address);
-                                DataExtractor data;
-                                size_t bytes_read = 0;
-                                std::vector<char> data_buffer;
-                                Error error;
-                                bool prefer_file_cache = false;
-                                if (cstr_len > 0)
-                                {
-                                    data_buffer.resize(cstr_len);
-                                    data.SetData (&data_buffer.front(), data_buffer.size(), lldb::endian::InlHostByteOrder());
-                                    bytes_read = target->ReadMemory (cstr_so_addr, 
-                                                                     prefer_file_cache, 
-                                                                     &data_buffer.front(), 
-                                                                     cstr_len, 
-                                                                     error);
-                                    if (bytes_read > 0)
-                                    {
-                                        sstr << '"';
-                                        data.Dump (&sstr,
-                                                   0,                 // Start offset in "data"
-                                                   eFormatCharArray,  // Print as characters
-                                                   1,                 // Size of item (1 byte for a char!)
-                                                   bytes_read,        // How many bytes to print?
-                                                   UINT32_MAX,        // num per line
-                                                   LLDB_INVALID_ADDRESS,// base address
-                                                   0,                 // bitfield bit size
-                                                   0);                // bitfield bit offset
-                                        if (capped_data)
-                                            sstr << "...";
-                                        sstr << '"';
-                                    }
+                                    cstr_address = GetAddressOf (cstr_address_type, true);
                                 }
                                 else
                                 {
-                                    const size_t k_max_buf_size = 256;
-                                    data_buffer.resize (k_max_buf_size + 1);
-                                    // NULL terminate in case we don't get the entire C string
-                                    data_buffer.back() = '\0';
-
-                                    sstr << '"';
-
-                                    data.SetData (&data_buffer.front(), data_buffer.size(), endian::InlHostByteOrder());
-                                    while ((bytes_read = target->ReadMemory (cstr_so_addr, 
-                                                                             prefer_file_cache,
-                                                                             &data_buffer.front(), 
-                                                                             k_max_buf_size, 
-                                                                             error)) > 0)
-                                    {
-                                        size_t len = strlen(&data_buffer.front());
-                                        if (len == 0)
-                                            break;
-                                        if (len > bytes_read)
-                                            len = bytes_read;
-
-                                        data.Dump (&sstr,
-                                                   0,                 // Start offset in "data"
-                                                   eFormatCharArray,  // Print as characters
-                                                   1,                 // Size of item (1 byte for a char!)
-                                                   len,               // How many bytes to print?
-                                                   UINT32_MAX,        // num per line
-                                                   LLDB_INVALID_ADDRESS,// base address
-                                                   0,                 // bitfield bit size
-                                                   0);                // bitfield bit offset
-                                        
-                                        if (len < k_max_buf_size)
-                                            break;
-                                        cstr_so_addr.Slide (k_max_buf_size);
-                                    }
-                                    sstr << '"';
+                                    // We have a pointer
+                                    cstr_address = GetPointerValue (cstr_address_type, true);
                                 }
-                            }
-                        }
-                        
-                        if (sstr.GetSize() > 0)
-                            m_summary_str.assign (sstr.GetData(), sstr.GetSize());
-                    }
-                    else if (ClangASTContext::IsFunctionPointerType (clang_type))
-                    {
-                        AddressType func_ptr_address_type = eAddressTypeInvalid;
-                        lldb::addr_t func_ptr_address = GetPointerValue (func_ptr_address_type, true);
-
-                        if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
-                        {
-                            switch (func_ptr_address_type)
-                            {
-                            case eAddressTypeInvalid:
-                            case eAddressTypeFile:
-                                break;
-
-                            case eAddressTypeLoad:
+                                if (cstr_address != LLDB_INVALID_ADDRESS)
                                 {
-                                    Address so_addr;
-                                    Target *target = exe_scope->CalculateTarget();
-                                    if (target && target->GetSectionLoadList().IsEmpty() == false)
+                                    Address cstr_so_addr (NULL, cstr_address);
+                                    DataExtractor data;
+                                    size_t bytes_read = 0;
+                                    std::vector<char> data_buffer;
+                                    Error error;
+                                    bool prefer_file_cache = false;
+                                    if (cstr_len > 0)
                                     {
-                                        if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
+                                        data_buffer.resize(cstr_len);
+                                        data.SetData (&data_buffer.front(), data_buffer.size(), lldb::endian::InlHostByteOrder());
+                                        bytes_read = target->ReadMemory (cstr_so_addr, 
+                                                                         prefer_file_cache, 
+                                                                         &data_buffer.front(), 
+                                                                         cstr_len, 
+                                                                         error);
+                                        if (bytes_read > 0)
                                         {
-                                            so_addr.Dump (&sstr, 
-                                                          exe_scope, 
-                                                          Address::DumpStyleResolvedDescription, 
-                                                          Address::DumpStyleSectionNameOffset);
+                                            sstr << '"';
+                                            data.Dump (&sstr,
+                                                       0,                 // Start offset in "data"
+                                                       eFormatCharArray,  // Print as characters
+                                                       1,                 // Size of item (1 byte for a char!)
+                                                       bytes_read,        // How many bytes to print?
+                                                       UINT32_MAX,        // num per line
+                                                       LLDB_INVALID_ADDRESS,// base address
+                                                       0,                 // bitfield bit size
+                                                       0);                // bitfield bit offset
+                                            if (capped_data)
+                                                sstr << "...";
+                                            sstr << '"';
                                         }
                                     }
-                                }
-                                break;
+                                    else
+                                    {
+                                        const size_t k_max_buf_size = 256;
+                                        data_buffer.resize (k_max_buf_size + 1);
+                                        // NULL terminate in case we don't get the entire C string
+                                        data_buffer.back() = '\0';
 
-                            case eAddressTypeHost:
-                                break;
+                                        sstr << '"';
+
+                                        data.SetData (&data_buffer.front(), data_buffer.size(), endian::InlHostByteOrder());
+                                        while ((bytes_read = target->ReadMemory (cstr_so_addr, 
+                                                                                 prefer_file_cache,
+                                                                                 &data_buffer.front(), 
+                                                                                 k_max_buf_size, 
+                                                                                 error)) > 0)
+                                        {
+                                            size_t len = strlen(&data_buffer.front());
+                                            if (len == 0)
+                                                break;
+                                            if (len > bytes_read)
+                                                len = bytes_read;
+
+                                            data.Dump (&sstr,
+                                                       0,                 // Start offset in "data"
+                                                       eFormatCharArray,  // Print as characters
+                                                       1,                 // Size of item (1 byte for a char!)
+                                                       len,               // How many bytes to print?
+                                                       UINT32_MAX,        // num per line
+                                                       LLDB_INVALID_ADDRESS,// base address
+                                                       0,                 // bitfield bit size
+                                                       0);                // bitfield bit offset
+                                            
+                                            if (len < k_max_buf_size)
+                                                break;
+                                            cstr_so_addr.Slide (k_max_buf_size);
+                                        }
+                                        sstr << '"';
+                                    }
+                                }
                             }
+                            
+                            if (sstr.GetSize() > 0)
+                                m_summary_str.assign (sstr.GetData(), sstr.GetSize());
                         }
-                        if (sstr.GetSize() > 0)
+                        else if (ClangASTContext::IsFunctionPointerType (clang_type))
                         {
-                            m_summary_str.assign (1, '(');
-                            m_summary_str.append (sstr.GetData(), sstr.GetSize());
-                            m_summary_str.append (1, ')');
+                            AddressType func_ptr_address_type = eAddressTypeInvalid;
+                            lldb::addr_t func_ptr_address = GetPointerValue (func_ptr_address_type, true);
+
+                            if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS)
+                            {
+                                switch (func_ptr_address_type)
+                                {
+                                case eAddressTypeInvalid:
+                                case eAddressTypeFile:
+                                    break;
+
+                                case eAddressTypeLoad:
+                                    {
+                                        Address so_addr;
+                                        Target *target = exe_scope->CalculateTarget();
+                                        if (target && target->GetSectionLoadList().IsEmpty() == false)
+                                        {
+                                            if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr))
+                                            {
+                                                so_addr.Dump (&sstr, 
+                                                              exe_scope, 
+                                                              Address::DumpStyleResolvedDescription, 
+                                                              Address::DumpStyleSectionNameOffset);
+                                            }
+                                        }
+                                    }
+                                    break;
+
+                                case eAddressTypeHost:
+                                    break;
+                                }
+                            }
+                            if (sstr.GetSize() > 0)
+                            {
+                                m_summary_str.assign (1, '(');
+                                m_summary_str.append (sstr.GetData(), sstr.GetSize());
+                                m_summary_str.append (1, ')');
+                            }
                         }
                     }
                 }
@@ -960,34 +917,35 @@
                         clang_type_t clang_type = GetClangType ();
                         if (clang_type)
                         {
-                            StreamString sstr;
-                            Format format = GetFormat();
-                            if (format == eFormatDefault)                                
+                            if (m_last_value_format)
                             {
-                                if (m_last_value_format)
-                                    format = m_last_value_format->m_format;
-                                else
-                                    // force the system into using unsigned integers for bitfields
-                                    format = (m_is_bitfield_for_scalar ? eFormatUnsigned :
-                                    ClangASTType::GetFormat(clang_type));
+                                m_value_str = m_last_value_format->FormatObject(GetSP());
                             }
-
-                            if (ClangASTType::DumpTypeValue (GetClangAST(),            // The clang AST
-                                                             clang_type,               // The clang type to display
-                                                             &sstr,
-                                                             format,                   // Format to display this type with
-                                                             m_data,                   // Data to extract from
-                                                             0,                        // Byte offset into "m_data"
-                                                             GetByteSize(),            // Byte size of item in "m_data"
-                                                             GetBitfieldBitSize(),     // Bitfield bit size
-                                                             GetBitfieldBitOffset()))  // Bitfield bit offset
-                                m_value_str.swap(sstr.GetString());
                             else
                             {
-                                m_error.SetErrorStringWithFormat ("unsufficient data for value (only %u of %u bytes available)", 
-                                                                  m_data.GetByteSize(),
-                                                                  GetByteSize());
-                                m_value_str.clear();
+                                StreamString sstr;
+                                Format format = GetFormat();
+                                if (format == eFormatDefault)                                
+                                        format = (m_is_bitfield_for_scalar ? eFormatUnsigned :
+                                        ClangASTType::GetFormat(clang_type));
+
+                                if (ClangASTType::DumpTypeValue (GetClangAST(),            // The clang AST
+                                                                 clang_type,               // The clang type to display
+                                                                 &sstr,
+                                                                 format,                   // Format to display this type with
+                                                                 m_data,                   // Data to extract from
+                                                                 0,                        // Byte offset into "m_data"
+                                                                 GetByteSize(),            // Byte size of item in "m_data"
+                                                                 GetBitfieldBitSize(),     // Bitfield bit size
+                                                                 GetBitfieldBitOffset()))  // Bitfield bit offset
+                                    m_value_str.swap(sstr.GetString());
+                                else
+                                {
+                                    m_error.SetErrorStringWithFormat ("unsufficient data for value (only %u of %u bytes available)", 
+                                                                      m_data.GetByteSize(),
+                                                                      GetByteSize());
+                                    m_value_str.clear();
+                                }
                             }
                         }
                     }
@@ -1046,6 +1004,9 @@
         case eDisplayLanguageSpecific:
             return_value = GetObjectDescription();
             break;
+        case eDisplayLocation:
+            return_value = GetLocationAsCString();
+            break;
     }
     
     // this code snippet might lead to endless recursion, thus we use a RefCounter here to
@@ -3221,3 +3182,12 @@
         
     return needs_update;
 }
+
+void
+ValueObject::ClearUserVisibleData()
+{
+    m_location_str.clear();
+    m_value_str.clear();
+    m_summary_str.clear();
+    m_object_desc_str.clear();
+}
\ No newline at end of file
diff --git a/source/Interpreter/ScriptInterpreter.cpp b/source/Interpreter/ScriptInterpreter.cpp
index 7011c2e..294aeec 100644
--- a/source/Interpreter/ScriptInterpreter.cpp
+++ b/source/Interpreter/ScriptInterpreter.cpp
@@ -92,10 +92,12 @@
 
 void
 ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
-                                          SWIGBreakpointCallbackFunction python_swig_breakpoint_callback)
+                                          SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
+                                          SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback)
 {
     ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback, 
-                                                    python_swig_breakpoint_callback);
+                                                    python_swig_breakpoint_callback,
+                                                    python_swig_typescript_callback);
 }
 
 void
diff --git a/source/Interpreter/ScriptInterpreterPython.cpp b/source/Interpreter/ScriptInterpreterPython.cpp
index 610c019..57a5929 100644
--- a/source/Interpreter/ScriptInterpreterPython.cpp
+++ b/source/Interpreter/ScriptInterpreterPython.cpp
@@ -34,6 +34,7 @@
 
 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 @@
     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 @@
     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 @@
 
 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
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 0619c10..9712d6f 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Core/Log.h"
 #include "lldb/Core/State.h"
 #include "lldb/Core/StreamString.h"
+#include "lldb/Host/Endian.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/TimeValue.h"
 #include "lldb/Target/Process.h"
diff --git a/test/functionalities/data-formatter/data-formatter-script/Makefile b/test/functionalities/data-formatter/data-formatter-script/Makefile
new file mode 100644
index 0000000..314f1cb
--- /dev/null
+++ b/test/functionalities/data-formatter/data-formatter-script/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py b/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py
new file mode 100644
index 0000000..77a0368
--- /dev/null
+++ b/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py
@@ -0,0 +1,110 @@
+"""
+Test lldb data formatter subsystem.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+
+class DataFormatterTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "data-formatter", "data-formatter-script")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    def test_with_dsym_and_run_command(self):
+        """Test data formatter commands."""
+        self.buildDsym()
+        self.data_formatter_commands()
+
+    def test_with_dwarf_and_run_command(self):
+        """Test data formatter commands."""
+        self.buildDwarf()
+        self.data_formatter_commands()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number to break at.
+        self.line = line_number('main.cpp', '// Set break point at this line.')
+
+    def data_formatter_commands(self):
+        """Test that that file and class static variables display correctly."""
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        self.expect("breakpoint set -f main.cpp -l %d" % self.line,
+                    BREAKPOINT_CREATED,
+            startstr = "Breakpoint created: 1: file ='main.cpp', line = %d, locations = 1" %
+                        self.line)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # This is the function to remove the custom formats in order to have a
+        # clean slate for the next test case.
+        def cleanup():
+            self.runCmd('type format clear', check=False)
+            self.runCmd('type summary clear', check=False)
+
+        # Execute the cleanup function during test case tear down.
+        self.addTearDownHook(cleanup)
+
+        # Set the script here to ease the formatting
+        script = 'a = valobj.GetChildMemberWithName(\'integer\'); a_val = a.GetValue(); str = \'Hello from Python, \' + a_val + \' time\'; return str + (\'!\' if a_val == \'1\' else \'s!\');'
+
+        self.runCmd("type summary add add i_am_cool -s \"%s\"" % script)
+
+        self.expect("frame variable one",
+            substrs = ['Hello from Python',
+                       '1 time!'])
+
+        self.expect("frame variable two",
+            substrs = ['Hello from Python',
+                       '4 times!'])
+        
+        self.runCmd("n"); # skip ahead to make values change
+
+        self.expect("frame variable three",
+            substrs = ['Hello from Python, 10 times!',
+                       'Hello from Python, 4 times!'])
+
+        self.runCmd("n"); # skip ahead to make values change
+    
+        self.expect("frame variable two",
+            substrs = ['Hello from Python',
+                       '1 time!'])
+
+        script = 'a = valobj.GetChildMemberWithName(\'integer\'); a_val = a.GetValue(); str = \'int says \' + a_val; return str;'
+
+        # Check that changes in the script are immediately reflected
+        self.runCmd("type summary add i_am_cool -s \"%s\"" % script)
+
+        self.expect("frame variable two",
+                    substrs = ['int says 1'])
+
+        # Change the summary
+        self.runCmd("type summary add -f \"int says ${var.integer}, and float says ${var.floating}\" i_am_cool")
+
+        self.expect("frame variable two",
+                    substrs = ['int says 1',
+                               'and float says 2.71'])
+        # Try it for pointers
+        self.expect("frame variable twoptr",
+                    substrs = ['int says 1',
+                               'and float says 2.71'])
+
+        # Force a failure for pointers
+        self.runCmd("type summary add i_am_cool -p -s \"%s\"" % script)
+
+        self.expect("frame variable twoptr", matching=False,
+                    substrs = ['and float says 2.71'])
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
diff --git a/test/functionalities/data-formatter/data-formatter-script/main.cpp b/test/functionalities/data-formatter/data-formatter-script/main.cpp
new file mode 100644
index 0000000..3570622
--- /dev/null
+++ b/test/functionalities/data-formatter/data-formatter-script/main.cpp
@@ -0,0 +1,49 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+struct i_am_cool
+{
+	int integer;
+	float floating;
+	char character;
+	i_am_cool(int I, float F, char C) :
+    integer(I), floating(F), character(C) {}
+	i_am_cool() : integer(1), floating(2), character('3') {}
+    
+};
+
+struct i_am_cooler
+{
+	i_am_cool first_cool;
+	i_am_cool second_cool;
+	float floating;
+	
+	i_am_cooler(int I1, int I2, float F1, float F2, char C1, char C2) :
+    first_cool(I1,F1,C1),
+    second_cool(I2,F2,C2),
+    floating((F1 + F2)/2) {}
+};
+
+int main (int argc, const char * argv[])
+{
+    i_am_cool one(1,3.14,'E');
+    i_am_cool two(4,2.71,'G');
+    
+    i_am_cool* twoptr = &two;
+    
+    i_am_cooler three(10,4,1985,1/1/2011,'B','E'); // Set break point at this line.
+    
+    two.integer = 1;
+    
+    return 0;
+}
\ No newline at end of file
diff --git a/www/varformats.html b/www/varformats.html
index b0a1af1..3fd647d 100755
--- a/www/varformats.html
+++ b/www/varformats.html
@@ -784,6 +784,17 @@
                   (i_am_cool) one = x=3<br>
                 </code> </p>
 
+			<p>When defining a named summmary, binding it to one or more types becomes optional.
+			Even if you bind the named summary to a type, and later change the summary string
+			for that type, the named summary will not be changed by that. You can delete
+			named summaries by using the <code>type summary delete</code> command, as if the
+			summary name was the datatype that the summary is applied to</p>
+			
+			<p>A summary attached to a variable using the </code>--summary</code> option,
+			has the same semantics that a custom format attached using the <code>-f</code>
+			option has: it stays attached till you attach a new one, or till you let
+			your program run again.</p>
+
             </div>
         </div>