> On Oct 19, 2015, at 4:18 PM, Zachary Turner via lldb-commits > <lldb-commits@lists.llvm.org> wrote: > > I think this is going to break the CMake build. Can you update the relevant > CMakeLists.txt file? > > Also, are there any tests for this?
This doesn't actually add a REPL for any of the languages that the current LLDB sources support. You could probably make a fake REPL just for testing, but that seems like make-work. Seems to me better to wait till an actual REPL shows up and write tests using that. Jim > > On Mon, Oct 19, 2015 at 4:13 PM Sean Callanan via lldb-commits > <lldb-commits@lists.llvm.org> wrote: > 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 ¤t_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 > + > _______________________________________________ > lldb-commits mailing list > lldb-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits