[Lldb-commits] [lldb] r250753 - Added the concept of a Read-Eval-Print-Loop to LLDB.

Sean Callanan via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 19 16:11:08 PDT 2015


Author: spyffe
Date: Mon Oct 19 18:11:07 2015
New Revision: 250753

URL: http://llvm.org/viewvc/llvm-project?rev=250753&view=rev
Log:
Added the concept of a Read-Eval-Print-Loop to LLDB.

A REPL takes over the command line and typically treats input as source code.
REPLs can also do code completion.  The REPL class allows its subclasses to
implement the language-specific functionality without having to know about the
IOHandler-specific internals.

Also added a PluginManager-based way of getting to a REPL given a language and
a target.

Also brought in some utility code and expression options that are useful for
REPLs, such as line offsets for expressions, ANSI terminal coloring of errors,
and a few IOHandler convenience functions.

Added:
    lldb/trunk/include/lldb/Expression/REPL.h
    lldb/trunk/source/Expression/REPL.cpp
Modified:
    lldb/trunk/include/lldb/Core/Debugger.h
    lldb/trunk/include/lldb/Core/IOHandler.h
    lldb/trunk/include/lldb/Core/PluginManager.h
    lldb/trunk/include/lldb/Expression/UserExpression.h
    lldb/trunk/include/lldb/Host/File.h
    lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
    lldb/trunk/include/lldb/Target/Target.h
    lldb/trunk/include/lldb/Utility/AnsiTerminal.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/include/lldb/lldb-private-interfaces.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Core/Debugger.cpp
    lldb/trunk/source/Core/PluginManager.cpp
    lldb/trunk/source/Expression/UserExpression.cpp
    lldb/trunk/source/Host/common/File.cpp
    lldb/trunk/source/Interpreter/CommandInterpreter.cpp
    lldb/trunk/source/Target/Target.cpp

Modified: lldb/trunk/include/lldb/Core/Debugger.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Debugger.h (original)
+++ lldb/trunk/include/lldb/Core/Debugger.h Mon Oct 19 18:11:07 2015
@@ -203,6 +203,10 @@ public:
     
     bool
     IsTopIOHandler (const lldb::IOHandlerSP& reader_sp);
+    
+    bool
+    CheckTopIOHandlerTypes (IOHandler::Type top_type,
+                            IOHandler::Type second_top_type);
 
     void
     PrintAsync (const char *s, size_t len, bool is_stdout);
@@ -322,6 +326,24 @@ public:
     GetAutoOneLineSummaries () const;
     
     bool
+    GetAutoIndent () const;
+    
+    bool
+    SetAutoIndent (bool b);
+    
+    bool
+    GetPrintDecls () const;
+    
+    bool
+    SetPrintDecls (bool b);
+    
+    uint32_t
+    GetTabSize () const;
+    
+    bool
+    SetTabSize (uint32_t tab_size);
+
+    bool
     GetEscapeNonPrintables () const;
     
     bool
@@ -362,6 +384,7 @@ public:
 protected:
 
     friend class CommandInterpreter;
+    friend class REPL;
 
     bool
     StartEventHandlerThread();
@@ -373,11 +396,17 @@ protected:
     EventHandlerThread (lldb::thread_arg_t arg);
 
     bool
+    HasIOHandlerThread();
+
+    bool
     StartIOHandlerThread();
     
     void
     StopIOHandlerThread();
     
+    void
+    JoinIOHandlerThread();
+    
     static lldb::thread_result_t
     IOHandlerThread (lldb::thread_arg_t arg);
 

Modified: lldb/trunk/include/lldb/Core/IOHandler.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/IOHandler.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/IOHandler.h (original)
+++ lldb/trunk/include/lldb/Core/IOHandler.h Mon Oct 19 18:11:07 2015
@@ -42,6 +42,7 @@ namespace lldb_private {
             Confirm,
             Curses,
             Expression,
+            REPL,
             ProcessIO,
             PythonInterpreter,
             PythonCode,

Modified: lldb/trunk/include/lldb/Core/PluginManager.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/PluginManager.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/PluginManager.h (original)
+++ lldb/trunk/include/lldb/Core/PluginManager.h Mon Oct 19 18:11:07 2015
@@ -444,6 +444,23 @@ public:
     GetTypeSystemEnumerateSupportedLanguagesCallbackForPluginName (const ConstString &name);
     
     //------------------------------------------------------------------
+    // REPL
+    //------------------------------------------------------------------
+    static bool
+    RegisterPlugin (const ConstString &name,
+                    const char *description,
+                    REPLCreateInstance create_callback);
+    
+    static bool
+    UnregisterPlugin (REPLCreateInstance create_callback);
+    
+    static REPLCreateInstance
+    GetREPLCreateCallbackAtIndex (uint32_t idx);
+    
+    static REPLCreateInstance
+    GetREPLCreateCallbackForPluginName (const ConstString &name);
+    
+    //------------------------------------------------------------------
     // Some plug-ins might register a DebuggerInitializeCallback
     // callback when registering the plug-in. After a new Debugger
     // instance is created, this DebuggerInitialize function will get

Added: lldb/trunk/include/lldb/Expression/REPL.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/REPL.h?rev=250753&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Expression/REPL.h (added)
+++ lldb/trunk/include/lldb/Expression/REPL.h Mon Oct 19 18:11:07 2015
@@ -0,0 +1,185 @@
+//===-- REPL.h --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef lldb_REPL_h
+#define lldb_REPL_h
+
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/../../source/Commands/CommandObjectExpression.h"
+
+namespace lldb_private
+{
+    
+class REPL : public IOHandlerDelegate
+{
+public:
+    //----------------------------------------------------------------------
+    // See TypeSystem.h for how to add subclasses to this.
+    //----------------------------------------------------------------------
+    enum LLVMCastKind {
+        eKindClang,
+        eKindSwift,
+        eKindGo,
+        kNumKinds
+    };
+    
+    LLVMCastKind getKind() const { return m_kind; }
+    
+    REPL(LLVMCastKind kind, Target &target);
+    
+    virtual ~REPL();
+    
+    static lldb::REPLSP
+    Create (lldb::LanguageType language, Target *target);
+
+    void
+    SetFormatOptions (const OptionGroupFormat &options)
+    {
+        m_format_options = options;
+    }
+    
+    void
+    SetValueObjectDisplayOptions (const OptionGroupValueObjectDisplay &options)
+    {
+        m_varobj_options = options;
+    }
+    
+    void
+    SetCommandOptions (const CommandObjectExpression::CommandOptions &options)
+    {
+        m_command_options = options;
+    }
+    
+    void
+    SetCompilerOptions (const char *options)
+    {
+        if (options)
+            m_compiler_options = options;
+    }
+    
+    lldb::IOHandlerSP
+    GetIOHandler ();
+    
+    Error
+    RunLoop ();
+    
+    //------------------------------------------------------------------
+    // IOHandler::Delegate functions
+    //------------------------------------------------------------------
+    void
+    IOHandlerActivated (IOHandler &io_handler) override;
+
+    bool
+    IOHandlerInterrupt (IOHandler &io_handler) override;
+    
+    void
+    IOHandlerInputInterrupted (IOHandler &io_handler,
+                               std::string &line) override;
+
+    const char *
+    IOHandlerGetFixIndentationCharacters () override;
+    
+    ConstString
+    IOHandlerGetControlSequence (char ch) override;
+    
+    const char *
+    IOHandlerGetCommandPrefix () override;
+    
+    const char *
+    IOHandlerGetHelpPrologue () override;
+    
+    bool
+    IOHandlerIsInputComplete (IOHandler &io_handler,
+                              StringList &lines) override;
+    
+    int
+    IOHandlerFixIndentation (IOHandler &io_handler,
+                             const StringList &lines,
+                             int cursor_position) override;
+    
+    void
+    IOHandlerInputComplete (IOHandler &io_handler,
+                            std::string &line) override;
+    
+    int
+    IOHandlerComplete (IOHandler &io_handler,
+                       const char *current_line,
+                       const char *cursor,
+                       const char *last_char,
+                       int skip_first_n_matches,
+                       int max_matches,
+                       StringList &matches) override;
+
+private:
+    std::string
+    GetSourcePath();
+    
+protected:
+    static int
+    CalculateActualIndentation (const StringList &lines);
+
+    //----------------------------------------------------------------------
+    // Subclasses should override these functions to implement a functional REPL.
+    //----------------------------------------------------------------------
+    
+    virtual Error
+    DoInitialization () = 0;
+    
+    virtual ConstString
+    GetSourceFileBasename () = 0;
+    
+    virtual const char *
+    GetAutoIndentCharacters () = 0;
+    
+    virtual bool
+    SourceIsComplete (const std::string &source) = 0;
+    
+    virtual lldb::offset_t
+    GetDesiredIndentation (const StringList &lines,
+                           int cursor_position,
+                           int tab_size) = 0; // LLDB_INVALID_OFFSET means no change
+    
+    virtual lldb::LanguageType
+    GetLanguage () = 0;
+    
+    virtual bool
+    PrintOneVariable (Debugger &debugger,
+                      lldb::StreamFileSP &output_sp,
+                      lldb::ValueObjectSP &valobj_sp,
+                      ExpressionVariable *var = nullptr) = 0;
+    
+    virtual int
+    CompleteCode(const std::string &current_code,
+                 StringList &matches) = 0;
+    
+    OptionGroupFormat m_format_options = OptionGroupFormat(lldb::eFormatDefault);
+    OptionGroupValueObjectDisplay m_varobj_options;
+    CommandObjectExpression::CommandOptions m_command_options;
+    std::string m_compiler_options;
+    
+    bool m_enable_auto_indent = true;
+    std::string m_indent_str; // Use this string for each level of indentation
+    std::string m_current_indent_str;
+    uint32_t m_current_indent_level = 0;
+    
+    std::string m_repl_source_path;
+    bool m_dedicated_repl_mode = false;
+    
+    StringList m_code; // All accumulated REPL statements are saved here
+    
+    Target &m_target;
+    lldb::IOHandlerSP m_io_handler_sp;
+    LLVMCastKind m_kind;
+};
+
+}
+
+#endif /* REPL_h */

Modified: lldb/trunk/include/lldb/Expression/UserExpression.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/UserExpression.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/UserExpression.h (original)
+++ lldb/trunk/include/lldb/Expression/UserExpression.h Mon Oct 19 18:11:07 2015
@@ -273,10 +273,16 @@ public:
     /// @param[in,out] result_valobj_sp
     ///      If execution is successful, the result valobj is placed here.
     ///
-    /// @param[out]
+    /// @param[out] error
     ///     Filled in with an error in case the expression evaluation
     ///     fails to parse, run, or evaluated.
     ///
+    /// @param[in] line_offset
+    ///     The offset of the first line of the expression from the "beginning" of a virtual source file used for error reporting and debug info.
+    ///
+    /// @param[out] jit_module_sp_ptr
+    ///     If non-NULL, used to persist the generated IR module.
+    ///
     /// @result
     ///      A Process::ExpressionResults value.  eExpressionCompleted for success.
     //------------------------------------------------------------------
@@ -286,7 +292,9 @@ public:
               const char *expr_cstr,
               const char *expr_prefix,
               lldb::ValueObjectSP &result_valobj_sp,
-              Error &error);
+              Error &error,
+              uint32_t line_offset = 0,
+              lldb::ModuleSP *jit_module_sp_ptr = NULL);
 
     static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression.
 protected:

Modified: lldb/trunk/include/lldb/Host/File.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/File.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/File.h (original)
+++ lldb/trunk/include/lldb/Host/File.h Mon Oct 19 18:11:07 2015
@@ -494,6 +494,9 @@ public:
     //------------------------------------------------------------------
     bool
     GetIsRealTerminal ();
+    
+    bool
+    GetIsTerminalWithColors ();
 
     //------------------------------------------------------------------
     /// Output printf formatted output to the stream.
@@ -546,6 +549,7 @@ protected:
     bool m_own_stream;
     LazyBool m_is_interactive;
     LazyBool m_is_real_terminal;
+    LazyBool m_supports_colors;
 };
 
 } // namespace lldb_private

Modified: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h Mon Oct 19 18:11:07 2015
@@ -659,6 +659,9 @@ public:
         return m_stopped_for_crash;
     }
     
+    bool
+    GetSpaceReplPrompts () const;
+    
 protected:
     friend class Debugger;
 

Modified: lldb/trunk/include/lldb/Target/Target.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Target.h (original)
+++ lldb/trunk/include/lldb/Target/Target.h Mon Oct 19 18:11:07 2015
@@ -442,6 +442,18 @@ public:
     }
     
     bool
+    GetColorizeErrors () const
+    {
+        return m_ansi_color_errors;
+    }
+    
+    void
+    SetColorizeErrors (bool b)
+    {
+        m_ansi_color_errors = b;
+    }
+    
+    bool
     GetTrapExceptions() const
     {
         return m_trap_exceptions;
@@ -453,6 +465,18 @@ public:
         m_trap_exceptions = b;
     }
     
+    bool
+    GetREPLEnabled() const
+    {
+        return m_repl;
+    }
+    
+    void
+    SetREPLEnabled (bool b)
+    {
+        m_repl = b;
+    }
+    
     void
     SetCancelCallback (lldb::ExpressionCancelCallback callback, void *baton)
     {
@@ -468,6 +492,37 @@ public:
         else
             return m_cancel_callback (phase, m_cancel_callback_baton);
     }
+    
+    // Allows the expression contents to be remapped to point to the specified file and line
+    // using #line directives.
+    void
+    SetPoundLine (const char *path, uint32_t line) const
+    {
+        if (path && path[0])
+        {
+            m_pound_line_file = path;
+            m_pound_line_line = line;
+        }
+        else
+        {
+            m_pound_line_file.clear();
+            m_pound_line_line = 0;
+        }
+    }
+    
+    const char *
+    GetPoundLineFilePath () const
+    {
+        if (m_pound_line_file.empty())
+            return NULL;
+        return m_pound_line_file.c_str();
+    }
+    
+    uint32_t
+    GetPoundLineLine () const
+    {
+        return m_pound_line_line;
+    }
 
     void
     SetResultIsInternal (bool b)
@@ -493,13 +548,20 @@ private:
     bool m_stop_others;
     bool m_debug;
     bool m_trap_exceptions;
+    bool m_repl;
     bool m_generate_debug_info;
+    bool m_ansi_color_errors;
     bool m_result_is_internal;
     lldb::DynamicValueType m_use_dynamic;
     uint32_t m_timeout_usec;
     uint32_t m_one_thread_timeout_usec;
     lldb::ExpressionCancelCallback m_cancel_callback;
     void *m_cancel_callback_baton;
+    // If m_pound_line_file is not empty and m_pound_line_line is non-zero,
+    // use #line %u "%s" before the expression content to remap where the source
+    // originates
+    mutable std::string m_pound_line_file;
+    mutable uint32_t m_pound_line_line;
 };
 
 //----------------------------------------------------------------------
@@ -1504,8 +1566,11 @@ public:
     
     lldb::SearchFilterSP
     GetSearchFilterForModuleAndCUList (const FileSpecList *containingModules, const FileSpecList *containingSourceFiles);
+    
+    lldb::REPLSP
+    GetREPL (lldb::LanguageType, bool can_create);
 
-protected:    
+protected:
     //------------------------------------------------------------------
     // Member variables.
     //------------------------------------------------------------------
@@ -1528,6 +1593,9 @@ protected:
     PathMappingList m_image_search_paths;
     TypeSystemMap m_scratch_type_system_map;
     
+    typedef std::map<lldb::LanguageType, lldb::REPLSP> REPLMap;
+    REPLMap m_repl_map;
+    
     lldb::ClangASTImporterUP m_ast_importer_ap;
     lldb::ClangModulesDeclVendorUP m_clang_modules_decl_vendor_ap;
 

Modified: lldb/trunk/include/lldb/Utility/AnsiTerminal.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Utility/AnsiTerminal.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Utility/AnsiTerminal.h (original)
+++ lldb/trunk/include/lldb/Utility/AnsiTerminal.h Mon Oct 19 18:11:07 2015
@@ -41,8 +41,13 @@
 #define ANSI_CTRL_CONCEAL           8
 #define ANSI_CTRL_CROSSED_OUT       9
 
-#define ANSI_ESC_START          "\033["
-#define ANSI_ESC_END            "m"
+#define ANSI_ESC_START              "\033["
+#define ANSI_ESC_END                "m"
+
+#define ANSI_STR(s)                 #s
+#define ANSI_DEF_STR(s)             ANSI_STR(s)
+
+#define ANSI_ESCAPE1(s)             ANSI_ESC_START ANSI_DEF_STR(s) ANSI_ESC_END
 
 #define ANSI_1_CTRL(ctrl1)          "\033["##ctrl1 ANSI_ESC_END
 #define ANSI_2_CTRL(ctrl1,ctrl2)    "\033["##ctrl1";"##ctrl2 ANSI_ESC_END

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Mon Oct 19 18:11:07 2015
@@ -183,6 +183,7 @@ class   RegisterLocation;
 class   RegisterLocationList;
 class   RegisterValue;
 class   RegularExpression;
+class   REPL;
 class   Scalar;
 class   ScriptInterpreter;
 class   ScriptInterpreterLocker;
@@ -382,6 +383,7 @@ namespace lldb {
     typedef std::shared_ptr<lldb_private::Queue> QueueSP;
     typedef std::weak_ptr<lldb_private::Queue> QueueWP;
     typedef std::shared_ptr<lldb_private::QueueItem> QueueItemSP;
+    typedef std::shared_ptr<lldb_private::REPL> REPLSP;
     typedef std::shared_ptr<lldb_private::ScriptSummaryFormat> ScriptSummaryFormatSP;
     typedef std::shared_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterSP;
     typedef std::unique_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterUP;

Modified: lldb/trunk/include/lldb/lldb-private-interfaces.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-interfaces.h?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-interfaces.h (original)
+++ lldb/trunk/include/lldb/lldb-private-interfaces.h Mon Oct 19 18:11:07 2015
@@ -49,6 +49,7 @@ namespace lldb_private
     typedef lldb::InstrumentationRuntimeType (*InstrumentationRuntimeGetType) ();
     typedef lldb::InstrumentationRuntimeSP (*InstrumentationRuntimeCreateInstance) (const lldb::ProcessSP &process_sp);
     typedef lldb::TypeSystemSP (*TypeSystemCreateInstance) (lldb::LanguageType language, Module *module, Target *target);
+    typedef lldb::REPLSP (*REPLCreateInstance) (lldb::LanguageType language, Target *target);
     typedef void (*TypeSystemEnumerateSupportedLanguages) (std::set<lldb::LanguageType> &languages_for_types, std::set<lldb::LanguageType> &languages_for_expressions);
     typedef int (*ComparisonFunction)(const void *, const void *);
     typedef void (*DebuggerInitializeCallback)(Debugger &debugger);

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Oct 19 18:11:07 2015
@@ -668,6 +668,7 @@
 		449ACC98197DEA0B008D175E /* FastDemangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 449ACC96197DE9EC008D175E /* FastDemangle.cpp */; };
 		490A36C0180F0E6F00BA31F8 /* PlatformWindows.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 490A36BD180F0E6F00BA31F8 /* PlatformWindows.cpp */; };
 		490A966B1628C3BF00F0002E /* SBDeclaration.h in Headers */ = {isa = PBXBuildFile; fileRef = 9452573816262CEF00325455 /* SBDeclaration.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		4939EA8D1BD56B6D00084382 /* REPL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4939EA8C1BD56B6D00084382 /* REPL.cpp */; };
 		494260DA14579144003C1C78 /* VerifyDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 494260D914579144003C1C78 /* VerifyDecl.cpp */; };
 		4959511F1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4959511E1A1BC4BC00F6F8FC /* ClangModulesDeclVendor.cpp */; };
 		4966DCC4148978A10028481B /* ClangExternalASTSourceCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4966DCC3148978A10028481B /* ClangExternalASTSourceCommon.cpp */; };
@@ -2254,6 +2255,8 @@
 		491193501226386000578B7F /* ASTStructExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTStructExtractor.cpp; path = ExpressionParser/Clang/ASTStructExtractor.cpp; sourceTree = "<group>"; };
 		49307AAD11DEA4D90081F992 /* IRForTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRForTarget.cpp; path = ExpressionParser/Clang/IRForTarget.cpp; sourceTree = "<group>"; };
 		49307AB111DEA4F20081F992 /* IRForTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRForTarget.h; path = ExpressionParser/Clang/IRForTarget.h; sourceTree = "<group>"; };
+		4939EA8B1BD56B3700084382 /* REPL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = REPL.h; path = include/lldb/Expression/REPL.h; sourceTree = "<group>"; };
+		4939EA8C1BD56B6D00084382 /* REPL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = REPL.cpp; path = source/Expression/REPL.cpp; sourceTree = "<group>"; };
 		494260D7145790D5003C1C78 /* VerifyDecl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = VerifyDecl.h; path = include/lldb/Symbol/VerifyDecl.h; sourceTree = "<group>"; };
 		494260D914579144003C1C78 /* VerifyDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerifyDecl.cpp; path = source/Symbol/VerifyDecl.cpp; sourceTree = "<group>"; };
 		49445C2512245E3600C11A81 /* ClangExpressionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExpressionParser.cpp; path = ExpressionParser/Clang/ClangExpressionParser.cpp; sourceTree = "<group>"; };
@@ -4447,6 +4450,8 @@
 				496B01581406DE8900F830D5 /* IRInterpreter.cpp */,
 				49DCF6FF170E6FD90092F75E /* Materializer.h */,
 				49DCF700170E70120092F75E /* Materializer.cpp */,
+				4939EA8B1BD56B3700084382 /* REPL.h */,
+				4939EA8C1BD56B6D00084382 /* REPL.cpp */,
 			);
 			name = Expression;
 			sourceTree = "<group>";
@@ -6371,6 +6376,7 @@
 				2689005F13353E0E00698AC0 /* ClangFunctionCaller.cpp in Sources */,
 				2689006013353E0E00698AC0 /* ClangExpressionDeclMap.cpp in Sources */,
 				2689006113353E0E00698AC0 /* ClangExpressionParser.cpp in Sources */,
+				4939EA8D1BD56B6D00084382 /* REPL.cpp in Sources */,
 				B5EFAE861AE53B1D007059F3 /* RegisterContextFreeBSD_arm.cpp in Sources */,
 				2689006313353E0E00698AC0 /* ClangPersistentVariables.cpp in Sources */,
 				2689006413353E0E00698AC0 /* ClangUserExpression.cpp in Sources */,

Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Mon Oct 19 18:11:07 2015
@@ -156,6 +156,9 @@ g_properties[] =
 {   "use-external-editor",      OptionValue::eTypeBoolean     , true, false, NULL, NULL, "Whether to use an external editor or not." },
 {   "use-color",                OptionValue::eTypeBoolean     , true, true , NULL, NULL, "Whether to use Ansi color codes or not." },
 {   "auto-one-line-summaries",  OptionValue::eTypeBoolean     , true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." },
+{   "auto-indent",              OptionValue::eTypeBoolean     , true, true , NULL, NULL, "If true, LLDB will auto indent/outdent code. Currently only supported in the REPL (default: true)." },
+{   "print-decls",              OptionValue::eTypeBoolean     , true, true , NULL, NULL, "If true, LLDB will print the values of variables declared in an expression. Currently only supported in the REPL (default: true)." },
+{   "tab-size",                 OptionValue::eTypeUInt64      , true, 4    , NULL, NULL, "The tab size to use when indenting code in multi-line input mode (default: 4)." },
 {   "escape-non-printables",    OptionValue::eTypeBoolean     , true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." },
 {   NULL,                       OptionValue::eTypeInvalid     , true, 0    , NULL, NULL, NULL }
 };
@@ -177,6 +180,9 @@ enum
     ePropertyUseExternalEditor,
     ePropertyUseColor,
     ePropertyAutoOneLineSummaries,
+    ePropertyAutoIndent,
+    ePropertyPrintDecls,
+    ePropertyTabSize,
     ePropertyEscapeNonPrintables
 };
 
@@ -392,6 +398,49 @@ Debugger::GetEscapeNonPrintables () cons
     return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true);
 }
 
+bool
+Debugger::GetAutoIndent () const
+{
+    const uint32_t idx = ePropertyAutoIndent;
+    return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true);
+}
+
+bool
+Debugger::SetAutoIndent (bool b)
+{
+    const uint32_t idx = ePropertyAutoIndent;
+    return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+bool
+Debugger::GetPrintDecls () const
+{
+    const uint32_t idx = ePropertyPrintDecls;
+    return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true);
+}
+
+bool
+Debugger::SetPrintDecls (bool b)
+{
+    const uint32_t idx = ePropertyPrintDecls;
+    return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+uint32_t
+Debugger::GetTabSize () const
+{
+    const uint32_t idx = ePropertyTabSize;
+    return m_collection_sp->GetPropertyAtIndexAsUInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+bool
+Debugger::SetTabSize (uint32_t tab_size)
+{
+    const uint32_t idx = ePropertyTabSize;
+    return m_collection_sp->SetPropertyAtIndexAsUInt64 (NULL, idx, tab_size);
+}
+
+
 #pragma mark Debugger
 
 //const DebuggerPropertiesSP &
@@ -919,6 +968,12 @@ Debugger::IsTopIOHandler (const lldb::IO
     return m_input_reader_stack.IsTop (reader_sp);
 }
 
+bool
+Debugger::CheckTopIOHandlerTypes (IOHandler::Type top_type, IOHandler::Type second_top_type)
+{
+    return m_input_reader_stack.CheckTopIOHandlerTypes (top_type, second_top_type);
+}
+
 void
 Debugger::PrintAsync (const char *s, size_t len, bool is_stdout)
 {
@@ -1684,6 +1739,12 @@ Debugger::IOHandlerThread (lldb::thread_
 }
 
 bool
+Debugger::HasIOHandlerThread()
+{
+    return m_io_handler_thread.IsJoinable();
+}
+
+bool
 Debugger::StartIOHandlerThread()
 {
     if (!m_io_handler_thread.IsJoinable())
@@ -1706,6 +1767,17 @@ Debugger::StopIOHandlerThread()
     }
 }
 
+void
+Debugger::JoinIOHandlerThread()
+{
+    if (HasIOHandlerThread())
+    {
+        thread_result_t result;
+        m_io_handler_thread.Join(&result);
+        m_io_handler_thread = LLDB_INVALID_HOST_THREAD;
+    }
+}
+
 Target *
 Debugger::GetDummyTarget()
 {

Modified: lldb/trunk/source/Core/PluginManager.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/PluginManager.cpp?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/source/Core/PluginManager.cpp (original)
+++ lldb/trunk/source/Core/PluginManager.cpp Mon Oct 19 18:11:07 2015
@@ -2648,6 +2648,106 @@ PluginManager::GetTypeSystemEnumerateSup
     return NULL;
 }
 
+#pragma mark REPL
+
+struct REPLInstance
+{
+    REPLInstance() :
+    name(),
+    description(),
+    create_callback(NULL)
+    {
+    }
+    
+    ConstString name;
+    std::string description;
+    REPLCreateInstance create_callback;
+};
+
+typedef std::vector<REPLInstance> REPLInstances;
+
+static Mutex &
+GetREPLMutex ()
+{
+    static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+    return g_instances_mutex;
+}
+
+static REPLInstances &
+GetREPLInstances ()
+{
+    static REPLInstances g_instances;
+    return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+                               const char *description,
+                               REPLCreateInstance create_callback)
+{
+    if (create_callback)
+    {
+        REPLInstance instance;
+        assert ((bool)name);
+        instance.name = name;
+        if (description && description[0])
+            instance.description = description;
+        instance.create_callback = create_callback;
+        Mutex::Locker locker (GetREPLMutex ());
+        GetREPLInstances ().push_back (instance);
+    }
+    return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (REPLCreateInstance create_callback)
+{
+    if (create_callback)
+    {
+        Mutex::Locker locker (GetREPLMutex ());
+        REPLInstances &instances = GetREPLInstances ();
+        
+        REPLInstances::iterator pos, end = instances.end();
+        for (pos = instances.begin(); pos != end; ++ pos)
+        {
+            if (pos->create_callback == create_callback)
+            {
+                instances.erase(pos);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+REPLCreateInstance
+PluginManager::GetREPLCreateCallbackAtIndex (uint32_t idx)
+{
+    Mutex::Locker locker (GetREPLMutex ());
+    REPLInstances &instances = GetREPLInstances ();
+    if (idx < instances.size())
+        return instances[idx].create_callback;
+    return NULL;
+}
+
+REPLCreateInstance
+PluginManager::GetREPLCreateCallbackForPluginName (const ConstString &name)
+{
+    if (name)
+    {
+        Mutex::Locker locker (GetREPLMutex ());
+        REPLInstances &instances = GetREPLInstances ();
+        
+        REPLInstances::iterator pos, end = instances.end();
+        for (pos = instances.begin(); pos != end; ++ pos)
+        {
+            if (name == pos->name)
+                return pos->create_callback;
+        }
+    }
+    return NULL;
+}
+
 #pragma mark PluginManager
 
 void

Added: lldb/trunk/source/Expression/REPL.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/REPL.cpp?rev=250753&view=auto
==============================================================================
--- lldb/trunk/source/Expression/REPL.cpp (added)
+++ lldb/trunk/source/Expression/REPL.cpp Mon Oct 19 18:11:07 2015
@@ -0,0 +1,650 @@
+//===-- REPL.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Expression/REPL.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/AnsiTerminal.h"
+
+using namespace lldb_private;
+
+lldb::REPLSP
+REPL::Create(lldb::LanguageType language, Target *target)
+{
+    uint32_t idx = 0;
+    lldb::REPLSP ret;
+    
+    while (REPLCreateInstance create_instance = PluginManager::GetREPLCreateCallbackAtIndex(idx++))
+    {
+        ret = (*create_instance)(language, target);
+        if (ret)
+        {
+            break;
+        }
+    }
+    
+    return ret;
+}
+
+REPL::REPL(LLVMCastKind kind, Target &target) :
+    m_target(target),
+    m_kind(kind)
+{
+    // Make sure all option values have sane defaults
+    Debugger &debugger = m_target.GetDebugger();
+    CommandInterpreter &ci = debugger.GetCommandInterpreter();
+    m_format_options.OptionParsingStarting(ci);
+    m_varobj_options.OptionParsingStarting(ci);
+    m_command_options.OptionParsingStarting(ci);
+    
+    // Default certain settings for REPL regardless of the global settings.
+    m_command_options.unwind_on_error = false;
+    m_command_options.ignore_breakpoints = false;
+    m_command_options.debug = false;
+}
+
+std::string
+REPL::GetSourcePath()
+{
+    ConstString file_basename = GetSourceFileBasename();
+    
+    FileSpec tmpdir_file_spec;
+    if (HostInfo::GetLLDBPath (lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+    {
+        tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString());
+        m_repl_source_path = std::move(tmpdir_file_spec.GetPath());
+    }
+    else
+    {
+        tmpdir_file_spec = FileSpec("/tmp", false);
+        tmpdir_file_spec.AppendPathComponent(file_basename.AsCString());
+    }
+    
+    return tmpdir_file_spec.GetPath();
+}
+
+REPL::~REPL()
+{
+}
+
+lldb::IOHandlerSP
+REPL::GetIOHandler()
+{
+    if (!m_io_handler_sp)
+    {
+        Debugger &debugger = m_target.GetDebugger();
+        m_io_handler_sp.reset (new IOHandlerEditline (debugger,
+                                                      IOHandler::Type::REPL,
+                                                      "lldb-repl",     // Name of input reader for history
+                                                      "> ",             // prompt
+                                                      ". ",             // Continuation prompt
+                                                      true,             // Multi-line
+                                                      true,             // The REPL prompt is always colored
+                                                      1,                // Line number
+                                                      *this));
+        
+        // Don't exit if CTRL+C is pressed
+        static_cast<IOHandlerEditline *>(m_io_handler_sp.get())->SetInterruptExits(false);
+        
+        if (m_io_handler_sp->GetIsInteractive() && m_io_handler_sp->GetIsRealTerminal())
+        {
+            m_indent_str.assign (debugger.GetTabSize(), ' ');
+            m_enable_auto_indent = debugger.GetAutoIndent();
+        }
+        else
+        {
+            m_indent_str.clear();
+            m_enable_auto_indent = false;
+        }
+        
+    }
+    return m_io_handler_sp;
+}
+
+void
+REPL::IOHandlerActivated (IOHandler &io_handler)
+{
+    lldb::ProcessSP process_sp = m_target.GetProcessSP();
+    if (process_sp && process_sp->IsAlive())
+        return;
+    lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
+    error_sp->Printf("REPL requires a running target process.\n");
+    io_handler.SetIsDone(true);
+}
+
+bool
+REPL::IOHandlerInterrupt (IOHandler &io_handler)
+{
+    return false;
+}
+
+void
+REPL::IOHandlerInputInterrupted (IOHandler &io_handler,
+                                 std::string &line)
+{
+}
+
+const char *
+REPL::IOHandlerGetFixIndentationCharacters ()
+{
+    if (m_enable_auto_indent)
+        return GetAutoIndentCharacters();
+    return NULL;
+}
+
+ConstString
+REPL::IOHandlerGetControlSequence (char ch)
+{
+    if (ch == 'd')
+        return ConstString(":quit\n");
+    return ConstString();
+}
+
+const char *
+REPL::IOHandlerGetCommandPrefix ()
+{
+    return ":";
+}
+
+const char *
+REPL::IOHandlerGetHelpPrologue ()
+{
+    return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter.  "
+    "Valid statements, expressions, and declarations are immediately compiled and executed.\n\n"
+    "The complete set of LLDB debugging commands are also available as described below.  Commands "
+    "must be prefixed with a colon at the REPL prompt (:quit for example.)  Typing just a colon "
+    "followed by return will switch to the LLDB prompt.\n\n";
+}
+
+bool
+REPL::IOHandlerIsInputComplete (IOHandler &io_handler,
+                                StringList &lines)
+{
+    // Check for meta command
+    const size_t num_lines = lines.GetSize();
+    if (num_lines == 1)
+    {
+        const char *first_line = lines.GetStringAtIndex(0);
+        if (first_line[0] == ':')
+            return true; // Meta command is a single line where that starts with ':'
+    }
+    
+    // Check if REPL input is done
+    std::string source_string (lines.CopyList());
+    return SourceIsComplete(source_string);
+}
+
+int
+REPL::CalculateActualIndentation (const StringList &lines)
+{
+    std::string last_line = lines[lines.GetSize() - 1];
+
+    int actual_indent = 0;
+    for (char &ch : last_line)
+    {
+        if (ch != ' ') break;
+        ++actual_indent;
+    }
+    
+    return actual_indent;
+}
+
+int
+REPL::IOHandlerFixIndentation (IOHandler &io_handler,
+                               const StringList &lines,
+                               int cursor_position)
+{
+    if (!m_enable_auto_indent) return 0;
+    
+    if (!lines.GetSize())
+    {
+        return 0;
+    }
+    
+    int tab_size = io_handler.GetDebugger().GetTabSize();
+
+    lldb::offset_t desired_indent = GetDesiredIndentation(lines,
+                                                          cursor_position,
+                                                          tab_size);
+    
+    int actual_indent = REPL::CalculateActualIndentation(lines);
+    
+    if (desired_indent == LLDB_INVALID_OFFSET)
+        return 0;
+    
+    return (int)desired_indent - actual_indent;
+}
+
+void
+REPL::IOHandlerInputComplete (IOHandler &io_handler, std::string &code)
+{
+    lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile());
+    lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
+    bool extra_line = false;
+    bool did_quit = false;
+    
+    if (code.empty())
+    {
+        m_code.AppendString("");
+        static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1);
+    }
+    else
+    {
+        Debugger &debugger = m_target.GetDebugger();
+        CommandInterpreter &ci = debugger.GetCommandInterpreter();
+        extra_line = ci.GetSpaceReplPrompts();
+        
+        ExecutionContext exe_ctx (m_target.GetProcessSP()->GetThreadList().GetSelectedThread()->GetSelectedFrame().get());
+        
+        lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
+        
+        if (code[0] == ':')
+        {
+            // Meta command
+            // Strip the ':'
+            code.erase(0, 1);
+            if (Args::StripSpaces (code))
+            {
+                // "lldb" was followed by arguments, so just execute the command dump the results
+                
+                // Turn off prompt on quit in case the user types ":quit"
+                const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
+                if (saved_prompt_on_quit)
+                    ci.SetPromptOnQuit(false);
+                
+                // Execute the command
+                CommandReturnObject result;
+                result.SetImmediateOutputStream(output_sp);
+                result.SetImmediateErrorStream(error_sp);
+                ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
+                
+                if (saved_prompt_on_quit)
+                    ci.SetPromptOnQuit(true);
+                
+                if (result.GetStatus() == lldb::eReturnStatusQuit)
+                {
+                    did_quit = true;
+                    io_handler.SetIsDone(true);
+                    if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter))
+                    {
+                        // We typed "quit" or an alias to quit so we need to check if the
+                        // command interpreter is above us and tell it that it is done as well
+                        // so we don't drop back into the command interpreter if we have already
+                        // quit
+                        lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
+                        if (io_handler_sp)
+                            io_handler_sp->SetIsDone(true);
+                    }
+                }
+            }
+            else
+            {
+                // ":" was followed by no arguments, so push the LLDB command prompt
+                if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter))
+                {
+                    // If the user wants to get back to the command interpreter and the
+                    // command interpreter is what launched the REPL, then just let the
+                    // REPL exit and fall back to the command interpreter.
+                    io_handler.SetIsDone(true);
+                }
+                else
+                {
+                    // The REPL wasn't launched the by the command interpreter, it is the
+                    // base IOHandler, so we need to get the command interpreter and
+                    lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
+                    if (io_handler_sp)
+                    {
+                        io_handler_sp->SetIsDone(false);
+                        debugger.PushIOHandler(ci.GetIOHandler());
+                    }
+                }
+            }
+        }
+        else
+        {
+            // Unwind any expression we might have been running in case our REPL
+            // expression crashed and the user was looking around
+            if (m_dedicated_repl_mode)
+            {
+                Thread *thread = exe_ctx.GetThreadPtr();
+                if (thread && thread->UnwindInnermostExpression().Success())
+                {
+                    thread->SetSelectedFrameByIndex(0, false);
+                    exe_ctx.SetFrameSP(thread->GetSelectedFrame());
+                }
+            }
+            
+            const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
+            
+            EvaluateExpressionOptions expr_options;
+            expr_options.SetCoerceToId(m_varobj_options.use_objc);
+            expr_options.SetUnwindOnError(m_command_options.unwind_on_error);
+            expr_options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
+            expr_options.SetKeepInMemory(true);
+            expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
+            expr_options.SetTryAllThreads(m_command_options.try_all_threads);
+            expr_options.SetGenerateDebugInfo(true);
+            expr_options.SetREPLEnabled (true);
+            expr_options.SetColorizeErrors(colorize_err);
+            expr_options.SetPoundLine(m_repl_source_path.c_str(), m_code.GetSize() + 1);
+            if (m_command_options.timeout > 0)
+                expr_options.SetTimeoutUsec(m_command_options.timeout);
+            else
+                expr_options.SetTimeoutUsec(0);
+            
+            expr_options.SetLanguage(GetLanguage());
+            
+            PersistentExpressionState *persistent_state = m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
+            
+            const size_t var_count_before = persistent_state->GetSize();
+            
+            const char *expr_prefix = NULL;
+            lldb::ValueObjectSP result_valobj_sp;
+            Error error;
+            lldb::ModuleSP jit_module_sp;
+            lldb::ExpressionResults execution_results = UserExpression::Evaluate (exe_ctx,
+                                                                                  expr_options,
+                                                                                  code.c_str(),
+                                                                                  expr_prefix,
+                                                                                  result_valobj_sp,
+                                                                                  error,
+                                                                                  0, // Line offset
+                                                                                  &jit_module_sp);
+            
+            //CommandInterpreter &ci = debugger.GetCommandInterpreter();
+            
+            if (process_sp && process_sp->IsAlive())
+            {
+                bool add_to_code = true;
+                bool handled = false;
+                if (result_valobj_sp)
+                {
+                    lldb::Format format = m_format_options.GetFormat();
+                    
+                    if (result_valobj_sp->GetError().Success())
+                    {
+                        handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
+                    }
+                    else if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult)
+                    {
+                        if (format != lldb::eFormatVoid && debugger.GetNotifyVoid())
+                        {
+                            error_sp->PutCString("(void)\n");
+                            handled = true;
+                        }
+                    }
+                }
+                
+                if (debugger.GetPrintDecls())
+                {
+                    for (size_t vi = var_count_before, ve = persistent_state->GetSize();
+                         vi != ve;
+                         ++vi)
+                    {
+                        lldb::ExpressionVariableSP persistent_var_sp = persistent_state->GetVariableAtIndex(vi);
+                        lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
+                        
+                        PrintOneVariable(debugger, output_sp, valobj_sp, persistent_var_sp.get());
+                    }
+                }
+                
+                
+                if (!handled)
+                {
+                    bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
+                    switch (execution_results)
+                    {
+                        case lldb::eExpressionSetupError:
+                        case lldb::eExpressionParseError:
+                            add_to_code = false;
+                            // Fall through
+                        case lldb::eExpressionDiscarded:
+                            error_sp->Printf("%s\n", error.AsCString());
+                            break;
+                            
+                        case lldb::eExpressionCompleted:
+                            break;
+                        case lldb::eExpressionInterrupted:
+                            if (useColors) {
+                                error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
+                                error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
+                            }
+                            error_sp->Printf("Execution interrupted. ");
+                            if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
+                            error_sp->Printf("Enter code to recover and continue.\nEnter LLDB commands to investigate (type :help for assistance.)\n");
+                            break;
+                            
+                        case lldb::eExpressionHitBreakpoint:
+                            // Breakpoint was hit, drop into LLDB command interpreter
+                            if (useColors) {
+                                error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
+                                error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
+                            }
+                            output_sp->Printf("Execution stopped at breakpoint.  ");
+                            if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
+                            output_sp->Printf("Enter LLDB commands to investigate (type help for assistance.)\n");
+                        {
+                            lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
+                            if (io_handler_sp)
+                            {
+                                io_handler_sp->SetIsDone(false);
+                                debugger.PushIOHandler(ci.GetIOHandler());
+                            }
+                        }
+                            break;
+                            
+                        case lldb::eExpressionTimedOut:
+                            error_sp->Printf("error: timeout\n");
+                            if (error.AsCString())
+                                error_sp->Printf("error: %s\n", error.AsCString());
+                            break;
+                        case lldb::eExpressionResultUnavailable:
+                            // Shoulnd't happen???
+                            error_sp->Printf("error: could not fetch result -- %s\n", error.AsCString());
+                            break;
+                        case lldb::eExpressionStoppedForDebug:
+                            // Shoulnd't happen???
+                            error_sp->Printf("error: stopped for debug -- %s\n", error.AsCString());
+                            break;
+                    }
+                }
+                
+                if (add_to_code)
+                {
+                    const uint32_t new_default_line = m_code.GetSize() + 1;
+                    
+                    m_code.SplitIntoLines(code);
+                    
+                    // Update our code on disk
+                    if (!m_repl_source_path.empty())
+                    {
+                        lldb_private::File file (m_repl_source_path.c_str(),
+                                                 File::eOpenOptionWrite | File::eOpenOptionTruncate | File::eOpenOptionCanCreate,
+                                                 lldb::eFilePermissionsFileDefault);
+                        std::string code (m_code.CopyList());
+                        code.append(1, '\n');
+                        size_t bytes_written = code.size();
+                        file.Write(code.c_str(), bytes_written);
+                        file.Close();
+                        
+                        // Now set the default file and line to the REPL source file
+                        m_target.GetSourceManager().SetDefaultFileAndLine(FileSpec(m_repl_source_path.c_str(), false), new_default_line);
+                    }
+                    static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1);
+                }
+                if (extra_line)
+                {
+                    fprintf(output_sp->GetFile().GetStream(), "\n");
+                }
+            }
+        }
+        
+        // Don't complain about the REPL process going away if we are in the process of quitting.
+        if (!did_quit && (!process_sp || !process_sp->IsAlive()))
+        {
+            error_sp->Printf("error: REPL process is no longer alive, exiting REPL\n");
+            io_handler.SetIsDone(true);
+        }
+    }
+}
+
+int
+REPL::IOHandlerComplete (IOHandler &io_handler,
+                         const char *current_line,
+                         const char *cursor,
+                         const char *last_char,
+                         int skip_first_n_matches,
+                         int max_matches,
+                         StringList &matches)
+{
+    matches.Clear();
+    
+    llvm::StringRef line (current_line, cursor - current_line);
+    
+    // Complete an LLDB command if the first character is a colon...
+    if (!line.empty() && line[0] == ':')
+    {
+        Debugger &debugger = m_target.GetDebugger();
+        
+        // auto complete LLDB commands
+        const char *lldb_current_line = line.substr(1).data();
+        return debugger.GetCommandInterpreter().HandleCompletion (lldb_current_line,
+                                                                  cursor,
+                                                                  last_char,
+                                                                  skip_first_n_matches,
+                                                                  max_matches,
+                                                                  matches);
+    }
+    
+    // Strip spaces from the line and see if we had only spaces
+    line = line.ltrim();
+    if (line.empty())
+    {
+        // Only spaces on this line, so just indent
+        matches.AppendString(m_indent_str);
+        return 1;
+    }
+    
+    std::string current_code;
+    current_code.append(m_code.CopyList());
+    
+    IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
+    const StringList *current_lines = editline.GetCurrentLines();
+    if (current_lines)
+    {
+        const uint32_t current_line_idx = editline.GetCurrentLineIndex();
+        
+        if (current_line_idx < current_lines->GetSize())
+        {
+            for (uint32_t i=0; i<current_line_idx; ++i)
+            {
+                const char *line_cstr = current_lines->GetStringAtIndex(i);
+                if (line_cstr)
+                {
+                    current_code.append("\n");
+                    current_code.append (line_cstr);
+                }
+            }
+        }
+    }
+    
+    if (cursor > current_line)
+    {
+        current_code.append("\n");
+        current_code.append(current_line, cursor - current_line);
+    }
+    
+    return CompleteCode(current_code, matches);
+}
+
+bool
+QuitCommandOverrideCallback(void *baton, const char **argv)
+{
+    Target *target = (Target *)baton;
+    lldb::ProcessSP process_sp (target->GetProcessSP());
+    if (process_sp)
+    {
+        process_sp->Destroy(false);
+        process_sp->GetTarget().GetDebugger().ClearIOHandlers();
+    }
+    return false;
+}
+
+Error
+REPL::RunLoop ()
+{
+    Error error;
+    
+    error = DoInitialization();
+    m_repl_source_path = GetSourcePath();
+    
+    if (!error.Success())
+        return error;
+    
+    Debugger &debugger = m_target.GetDebugger();
+    
+    lldb::IOHandlerSP io_handler_sp (GetIOHandler());
+    
+    FileSpec save_default_file;
+    uint32_t save_default_line = 0;
+    
+    if (!m_repl_source_path.empty())
+    {
+        // Save the current default file and line
+        m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file, save_default_line);
+    }
+    
+    debugger.PushIOHandler(io_handler_sp);
+    
+    // Check if we are in dedicated REPL mode where LLDB was start with the "--repl" option
+    // from the command line. Currently we know this by checking if the debugger already
+    // has a IOHandler thread.
+    if (!debugger.HasIOHandlerThread())
+    {
+        // The debugger doesn't have an existing IOHandler thread, so this must be
+        // dedicated REPL mode...
+        m_dedicated_repl_mode = true;
+        debugger.StartIOHandlerThread();
+        std::string command_name_str ("quit");
+        CommandObject *cmd_obj = debugger.GetCommandInterpreter().GetCommandObjectForCommand(command_name_str);
+        if (cmd_obj)
+        {
+            assert(command_name_str.empty());
+            cmd_obj->SetOverrideCallback (QuitCommandOverrideCallback, &m_target);
+        }
+    }
+    
+    // Wait for the REPL command interpreter to get popped
+    io_handler_sp->WaitForPop();
+    
+    if (m_dedicated_repl_mode)
+    {
+        // If we were in dedicated REPL mode we would have started the
+        // IOHandler thread, and we should kill our process
+        lldb::ProcessSP process_sp = m_target.GetProcessSP();
+        if (process_sp && process_sp->IsAlive())
+            process_sp->Destroy(false);
+        
+        // Wait for the IO handler thread to exit (TODO: don't do this if the IO handler thread already exists...)
+        debugger.JoinIOHandlerThread();
+    }
+    
+    // Restore the default file and line
+    if (save_default_file && save_default_line != 0)
+        m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file, save_default_line);
+    return error;
+}

Modified: lldb/trunk/source/Expression/UserExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/UserExpression.cpp?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/source/Expression/UserExpression.cpp (original)
+++ lldb/trunk/source/Expression/UserExpression.cpp Mon Oct 19 18:11:07 2015
@@ -465,7 +465,9 @@ UserExpression::Evaluate (ExecutionConte
                                const char *expr_cstr,
                                const char *expr_prefix,
                                lldb::ValueObjectSP &result_valobj_sp,
-                               Error &error)
+                               Error &error,
+                               uint32_t line_offset,
+                               lldb::ModuleSP *jit_module_sp_ptr)
 {
     Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
 
@@ -567,6 +569,10 @@ UserExpression::Evaluate (ExecutionConte
     }
     else
     {
+        // If a pointer to a lldb::ModuleSP was passed in, return the JIT'ed module if one was created
+        if (jit_module_sp_ptr && user_expression_sp->m_execution_unit_sp)
+            *jit_module_sp_ptr = user_expression_sp->m_execution_unit_sp->GetJITModule();
+
         lldb::ExpressionVariableSP expr_result;
 
         if (execution_policy == eExecutionPolicyNever &&

Modified: lldb/trunk/source/Host/common/File.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/File.cpp?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/File.cpp (original)
+++ lldb/trunk/source/Host/common/File.cpp Mon Oct 19 18:11:07 2015
@@ -22,6 +22,8 @@
 #include <sys/ioctl.h>
 #endif
 
+#include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
+
 #include "lldb/Core/DataBufferHeap.h"
 #include "lldb/Core/Error.h"
 #include "lldb/Core/Log.h"
@@ -1051,7 +1053,11 @@ File::CalculateInteractiveAndTerminal ()
             if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
             {
                 if (window_size.ws_col > 0)
+                {
                     m_is_real_terminal = eLazyBoolYes;
+                    if (llvm::sys::Process::FileDescriptorHasColors(fd))
+                        m_supports_colors = eLazyBoolYes;
+                }
             }
         }
 #endif
@@ -1074,3 +1080,11 @@ File::GetIsRealTerminal ()
     return m_is_real_terminal == eLazyBoolYes;
 }
 
+bool
+File::GetIsTerminalWithColors ()
+{
+    if (m_supports_colors == eLazyBoolCalculate)
+        CalculateInteractiveAndTerminal();
+    return m_supports_colors == eLazyBoolYes;
+}
+

Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Mon Oct 19 18:11:07 2015
@@ -85,6 +85,7 @@ g_properties[] =
     { "expand-regex-aliases", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." },
     { "prompt-on-quit", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." },
     { "stop-command-source-on-error", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, LLDB will stop running a 'command source' script upon encountering an error." },
+    { "space-repl-prompts", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, blank lines will be printed between between REPL submissions." },
     { nullptr                  , OptionValue::eTypeInvalid, true, 0    , nullptr, nullptr, nullptr }
 };
 
@@ -92,7 +93,8 @@ enum
 {
     ePropertyExpandRegexAliases = 0,
     ePropertyPromptOnQuit = 1,
-    ePropertyStopCmdSourceOnError = 2
+    ePropertyStopCmdSourceOnError = 2,
+    eSpaceReplPrompts = 3
 };
 
 ConstString &
@@ -167,6 +169,13 @@ CommandInterpreter::GetStopCmdSourceOnEr
     return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0);
 }
 
+bool
+CommandInterpreter::GetSpaceReplPrompts () const
+{
+    const uint32_t idx = eSpaceReplPrompts;
+    return m_collection_sp->GetPropertyAtIndexAsBoolean (nullptr, idx, g_properties[idx].default_uint_value != 0);
+}
+
 void
 CommandInterpreter::Initialize ()
 {

Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=250753&r1=250752&r2=250753&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Mon Oct 19 18:11:07 2015
@@ -31,6 +31,7 @@
 #include "lldb/Core/StreamString.h"
 #include "lldb/Core/Timer.h"
 #include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/REPL.h"
 #include "lldb/Expression/UserExpression.h"
 #include "Plugins/ExpressionParser/Clang/ClangASTSource.h"
 #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
@@ -211,6 +212,37 @@ Target::GetProcessSP () const
     return m_process_sp;
 }
 
+lldb::REPLSP
+Target::GetREPL (lldb::LanguageType language, bool can_create)
+{
+    if (language == eLanguageTypeUnknown)
+    {
+        return REPLSP(); // must provide a language
+    }
+    
+    REPLMap::iterator pos = m_repl_map.find(language);
+    
+    if (pos != m_repl_map.end())
+    {
+        return pos->second;
+    }
+    
+    if (!can_create)
+    {
+        return lldb::REPLSP();
+    }
+    
+    lldb::REPLSP ret = REPL::Create(language, this);
+    
+    if (ret)
+    {
+        m_repl_map[language] = ret;
+        return m_repl_map[language];
+    }
+    
+    return nullptr;
+}
+
 void
 Target::Destroy()
 {




More information about the lldb-commits mailing list