Index: .clang-format =================================================================== --- .clang-format +++ .clang-format @@ -4,5 +4,5 @@ BreakBeforeBraces: Allman AlwaysBreakAfterDefinitionReturnType: true AllowShortFunctionsOnASingleLine: Inline -BreakConstructorInitializersBeforeComma: true +ConstructorInitializerAllOnOneLineOrOnePerLine: true IndentCaseLabels: true Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -74,6 +74,7 @@ lldbPluginProcessElfCore lldbPluginJITLoaderGDB lldbPluginExpressionParserClang + lldbPluginExpressionParserGo ) # Windows-only libraries Index: include/lldb/Expression/LLVMUserExpression.h =================================================================== --- /dev/null +++ include/lldb/Expression/LLVMUserExpression.h @@ -0,0 +1,108 @@ +//===-- LLVMUserExpression.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LLVMUserExpression_h +#define liblldb_LLVMUserExpression_h + +// C Includes +// C++ Includes +#include +#include +#include + +// Project includes +#include "lldb/Expression/UserExpression.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +/// @class LLVMUserExpression LLVMUserExpression.h "lldb/Expression/LLVMUserExpression.h" +/// @brief Encapsulates a one-time expression for use in lldb. +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. LLVMUserExpression is a virtual base +/// class that encapsulates the objects needed to parse and JIT an expression. +/// The actual parsing part will be provided by the specific implementations +/// of LLVMUserExpression - which will be vended through the appropriate TypeSystem. +//---------------------------------------------------------------------- +class LLVMUserExpression : public UserExpression +{ + public: + LLVMUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type); + ~LLVMUserExpression() override; + + lldb::ExpressionResults Execute(Stream &error_stream, ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) override; + + bool FinalizeJITExecution(Stream &error_stream, ExecutionContext &exe_ctx, lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) override; + + bool + CanInterpret() override + { + return m_can_interpret; + } + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char * + Text() override + { + return m_transformed_text.c_str(); + } + + lldb::ModuleSP GetJITModule() override; + + protected: + virtual void ScanContext(ExecutionContext &exe_ctx, lldb_private::Error &err) = 0; + + bool PrepareToExecuteJITExpression(Stream &error_stream, ExecutionContext &exe_ctx, lldb::addr_t &struct_address); + virtual bool + AddInitialArguments(ExecutionContext &exe_ctx, std::vector &args, Stream &error_stream) + { + return true; + } + + lldb::addr_t m_stack_frame_bottom; ///< The bottom of the allocated stack frame. + lldb::addr_t m_stack_frame_top; ///< The top of the allocated stack frame. + + bool m_allow_cxx; ///< True if the language allows C++. + bool m_allow_objc; ///< True if the language allows Objective-C. + std::string m_transformed_text; ///< The text of the expression, as send to the parser + + std::shared_ptr m_execution_unit_sp; ///< The execution unit the expression is stored in. + std::unique_ptr m_materializer_ap; ///< The materializer to use when running the expression. + lldb::ModuleWP m_jit_module_wp; + bool m_enforce_valid_object; ///< True if the expression parser should enforce the presence of a valid class pointer + ///in order to generate the expression as a method. + bool m_in_cplusplus_method; ///< True if the expression is compiled as a C++ member function (true if it was parsed + ///when exe_ctx was in a C++ method). + bool m_in_objectivec_method; ///< True if the expression is compiled as an Objective-C method (true if it was parsed + ///when exe_ctx was in an Objective-C method). + bool m_in_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it + ///was parsed when exe_ctx was in an Objective-C class method). + bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression + ///doesn't really use them and they can be NULL. + bool m_const_object; ///< True if "this" is const. + Target *m_target; ///< The target for storing persistent data like types and variables. + + bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise. + lldb::addr_t + m_materialized_address; ///< The address at which the arguments to the expression have been materialized. + Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer. +}; + +} // namespace lldb_private +#endif Index: include/lldb/Expression/UserExpression.h =================================================================== --- include/lldb/Expression/UserExpression.h +++ include/lldb/Expression/UserExpression.h @@ -102,11 +102,7 @@ bool keep_result_in_memory, bool generate_debug_info) = 0; - bool - CanInterpret () - { - return m_can_interpret; - } + virtual bool CanInterpret() = 0; bool MatchesContext (ExecutionContext &exe_ctx); @@ -138,12 +134,10 @@ /// @return /// A Process::Execution results value. //------------------------------------------------------------------ - lldb::ExpressionResults - Execute (Stream &error_stream, - ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - lldb::UserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result); + virtual lldb::ExpressionResults Execute(Stream &error_stream, ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) = 0; //------------------------------------------------------------------ /// Apply the side effects of the function to program state. @@ -168,21 +162,18 @@ /// @return /// A Process::Execution results value. //------------------------------------------------------------------ - bool - FinalizeJITExecution (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::ExpressionVariableSP &result, - lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, - lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS); + virtual bool FinalizeJITExecution(Stream &error_stream, ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) = 0; //------------------------------------------------------------------ - /// Return the string that the parser should parse. Must be a full - /// translation unit. + /// Return the string that the parser should parse. //------------------------------------------------------------------ const char * Text() override { - return m_transformed_text.c_str(); + return m_expr_text.c_str(); } //------------------------------------------------------------------ @@ -251,6 +242,12 @@ return lldb::ExpressionVariableSP(); } + virtual lldb::ModuleSP + GetJITModule() + { + return lldb::ModuleSP(); + } + //------------------------------------------------------------------ /// Evaluate one expression in the scratch context of the /// target passed in the exe_ctx and return its result. @@ -307,23 +304,6 @@ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the environment. //------------------------------------------------------------------ - virtual void - ScanContext (ExecutionContext &exe_ctx, - lldb_private::Error &err) = 0; - - bool - PrepareToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::addr_t &struct_address); - - virtual bool - AddInitialArguments (ExecutionContext &exe_ctx, - std::vector &args, - Stream &error_stream) - { - return true; - } - void InstallContext (ExecutionContext &exe_ctx); @@ -334,31 +314,11 @@ lldb::StackFrameSP &frame_sp); Address m_address; ///< The address the process is stopped in. - lldb::addr_t m_stack_frame_bottom; ///< The bottom of the allocated stack frame. - lldb::addr_t m_stack_frame_top; ///< The top of the allocated stack frame. - std::string m_expr_text; ///< The text of the expression, as typed by the user std::string m_expr_prefix; ///< The text of the translation-level definitions, as provided by the user lldb::LanguageType m_language; ///< The language to use when parsing (eLanguageTypeUnknown means use defaults) - bool m_allow_cxx; ///< True if the language allows C++. - bool m_allow_objc; ///< True if the language allows Objective-C. - std::string m_transformed_text; ///< The text of the expression, as send to the parser ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression. - std::shared_ptr m_execution_unit_sp; ///< The execution unit the expression is stored in. - std::unique_ptr m_materializer_ap; ///< The materializer to use when running the expression. - lldb::ModuleWP m_jit_module_wp; - bool m_enforce_valid_object; ///< True if the expression parser should enforce the presence of a valid class pointer in order to generate the expression as a method. - bool m_in_cplusplus_method; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method). - bool m_in_objectivec_method; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method). - bool m_in_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it was parsed when exe_ctx was in an Objective-C class method). - bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression doesn't really use them and they can be NULL. - bool m_const_object; ///< True if "this" is const. - Target *m_target; ///< The target for storing persistent data like types and variables. - - bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise. - lldb::addr_t m_materialized_address; ///< The address at which the arguments to the expression have been materialized. - Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer. }; } // namespace lldb_private Index: include/lldb/Symbol/GoASTContext.h =================================================================== --- include/lldb/Symbol/GoASTContext.h +++ include/lldb/Symbol/GoASTContext.h @@ -249,8 +249,7 @@ lldb::BasicType GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) override; - CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, - size_t bit_size) override; + CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size) override; uint32_t GetNumFields(lldb::opaque_compiler_type_t type) override; @@ -388,6 +387,15 @@ const GoASTContext &operator=(const GoASTContext &) = delete; }; -} // namespace lldb_private +class GoASTContextForExpr : public GoASTContext +{ + public: + GoASTContextForExpr(lldb::TargetSP target) : m_target_wp(target) {} + UserExpression *GetUserExpression(const char *expr, const char *expr_prefix, lldb::LanguageType language, + Expression::ResultType desired_type) override; + private: + lldb::TargetWP m_target_wp; +}; +} #endif // liblldb_GoASTContext_h_ Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -830,10 +830,14 @@ 9AC703AF117675410086C050 /* SBInstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703AE117675410086C050 /* SBInstruction.cpp */; }; 9AC703B1117675490086C050 /* SBInstructionList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703B0117675490086C050 /* SBInstructionList.cpp */; }; A36FF33C17D8E94600244D40 /* OptionParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A36FF33B17D8E94600244D40 /* OptionParser.cpp */; }; + AE44FB301BB07EB20033EB62 /* GoUserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE44FB2C1BB07DD80033EB62 /* GoUserExpression.cpp */; }; + AE44FB311BB07EB80033EB62 /* GoLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE44FB2A1BB07DD80033EB62 /* GoLexer.cpp */; }; + AE44FB321BB07EBC0033EB62 /* GoParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE44FB2B1BB07DD80033EB62 /* GoParser.cpp */; }; AE44FB3E1BB485960033EB62 /* GoLanguageRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE44FB3D1BB485960033EB62 /* GoLanguageRuntime.cpp */; }; AE6897281B94F6DE0018845D /* DWARFASTParserGo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */; }; AE7F56291B8FE418001377A8 /* GoASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEFFBA7C1AC4835D0087B932 /* GoASTContext.cpp */; }; AE8F624919EF3E1E00326B21 /* OperatingSystemGo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE8F624719EF3E1E00326B21 /* OperatingSystemGo.cpp */; }; + AEB0E4591BD6E9F800B24093 /* LLVMUserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEB0E4581BD6E9F800B24093 /* LLVMUserExpression.cpp */; }; AEEA34051AC88A7400AB639D /* TypeSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEEA34041AC88A7400AB639D /* TypeSystem.cpp */; }; AF061F87182C97ED00B6A19C /* RegisterContextHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF061F85182C97ED00B6A19C /* RegisterContextHistory.cpp */; }; AF0C112818580CD800C4C45B /* QueueItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF0C112718580CD800C4C45B /* QueueItem.cpp */; }; @@ -2661,12 +2665,21 @@ 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointLocation.cpp; path = source/API/SBBreakpointLocation.cpp; sourceTree = ""; }; A36FF33B17D8E94600244D40 /* OptionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OptionParser.cpp; sourceTree = ""; }; A36FF33D17D8E98800244D40 /* OptionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionParser.h; path = include/lldb/Host/OptionParser.h; sourceTree = ""; }; + AE44FB261BB07DC60033EB62 /* GoAST.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoAST.h; path = ExpressionParser/Go/GoAST.h; sourceTree = ""; }; + AE44FB271BB07DC60033EB62 /* GoLexer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoLexer.h; path = ExpressionParser/Go/GoLexer.h; sourceTree = ""; }; + AE44FB281BB07DC60033EB62 /* GoParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoParser.h; path = ExpressionParser/Go/GoParser.h; sourceTree = ""; }; + AE44FB291BB07DC60033EB62 /* GoUserExpression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoUserExpression.h; path = ExpressionParser/Go/GoUserExpression.h; sourceTree = ""; }; + AE44FB2A1BB07DD80033EB62 /* GoLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoLexer.cpp; path = ExpressionParser/Go/GoLexer.cpp; sourceTree = ""; }; + AE44FB2B1BB07DD80033EB62 /* GoParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoParser.cpp; path = ExpressionParser/Go/GoParser.cpp; sourceTree = ""; }; + AE44FB2C1BB07DD80033EB62 /* GoUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoUserExpression.cpp; path = ExpressionParser/Go/GoUserExpression.cpp; sourceTree = ""; }; AE44FB3C1BB4858A0033EB62 /* GoLanguageRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoLanguageRuntime.h; path = Go/GoLanguageRuntime.h; sourceTree = ""; }; AE44FB3D1BB485960033EB62 /* GoLanguageRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GoLanguageRuntime.cpp; path = Go/GoLanguageRuntime.cpp; sourceTree = ""; }; AE6897261B94F6DE0018845D /* DWARFASTParserGo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFASTParserGo.cpp; sourceTree = ""; }; AE6897271B94F6DE0018845D /* DWARFASTParserGo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFASTParserGo.h; sourceTree = ""; }; AE8F624719EF3E1E00326B21 /* OperatingSystemGo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OperatingSystemGo.cpp; path = Go/OperatingSystemGo.cpp; sourceTree = ""; }; AE8F624819EF3E1E00326B21 /* OperatingSystemGo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OperatingSystemGo.h; path = Go/OperatingSystemGo.h; sourceTree = ""; }; + AEB0E4581BD6E9F800B24093 /* LLVMUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLVMUserExpression.cpp; path = source/Expression/LLVMUserExpression.cpp; sourceTree = ""; }; + AEB0E45A1BD6EA1400B24093 /* LLVMUserExpression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LLVMUserExpression.h; path = include/lldb/Expression/LLVMUserExpression.h; sourceTree = ""; }; AEEA33F61AC74FE700AB639D /* TypeSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TypeSystem.h; path = include/lldb/Symbol/TypeSystem.h; sourceTree = ""; }; AEEA34041AC88A7400AB639D /* TypeSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeSystem.cpp; path = source/Symbol/TypeSystem.cpp; sourceTree = ""; }; AEEA340F1ACA08A000AB639D /* GoASTContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GoASTContext.h; path = include/lldb/Symbol/GoASTContext.h; sourceTree = ""; }; @@ -4440,6 +4453,8 @@ 4C0083321B9A5DE200D5CF24 /* FunctionCaller.cpp */, 4C00832E1B9A58A700D5CF24 /* UserExpression.h */, 4C0083331B9A5DE200D5CF24 /* UserExpression.cpp */, + AEB0E45A1BD6EA1400B24093 /* LLVMUserExpression.h */, + AEB0E4581BD6E9F800B24093 /* LLVMUserExpression.cpp */, 4C00833D1B9F9B8400D5CF24 /* UtilityFunction.h */, 4C00833F1B9F9BA900D5CF24 /* UtilityFunction.cpp */, 49A1CAC11430E21D00306AC9 /* ExpressionSourceCode.h */, @@ -5120,6 +5135,7 @@ isa = PBXGroup; children = ( 4984BA0C1B97620B008658D4 /* Clang */, + AE44FB371BB35A2E0033EB62 /* Go */, ); name = ExpressionParser; sourceTree = ""; @@ -5493,6 +5509,20 @@ name = "SysV-mips"; sourceTree = ""; }; + AE44FB371BB35A2E0033EB62 /* Go */ = { + isa = PBXGroup; + children = ( + AE44FB261BB07DC60033EB62 /* GoAST.h */, + AE44FB271BB07DC60033EB62 /* GoLexer.h */, + AE44FB2A1BB07DD80033EB62 /* GoLexer.cpp */, + AE44FB281BB07DC60033EB62 /* GoParser.h */, + AE44FB2B1BB07DD80033EB62 /* GoParser.cpp */, + AE44FB291BB07DC60033EB62 /* GoUserExpression.h */, + AE44FB2C1BB07DD80033EB62 /* GoUserExpression.cpp */, + ); + name = Go; + sourceTree = ""; + }; AE44FB3B1BB485730033EB62 /* Go */ = { isa = PBXGroup; children = ( @@ -6228,6 +6258,7 @@ 2689FFDA13353D9D00698AC0 /* lldb.cpp in Sources */, 4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */, 26474CCD18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.cpp in Sources */, + AEB0E4591BD6E9F800B24093 /* LLVMUserExpression.cpp in Sources */, 2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */, 267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */, 2689FFF113353DB600698AC0 /* BreakpointID.cpp in Sources */, @@ -6358,6 +6389,7 @@ 3F81691A1ABA2419001DA9DF /* NameMatches.cpp in Sources */, 94B9E5121BBF20F4000A48DC /* NSString.cpp in Sources */, AF0E22F018A09FB20009B7D1 /* AppleGetItemInfoHandler.cpp in Sources */, + AE44FB301BB07EB20033EB62 /* GoUserExpression.cpp in Sources */, 2689004E13353E0400698AC0 /* Stream.cpp in Sources */, 2689004F13353E0400698AC0 /* StreamFile.cpp in Sources */, 2689005013353E0400698AC0 /* StreamString.cpp in Sources */, @@ -6476,6 +6508,7 @@ 949EEDA31BA76577008C63CF /* Cocoa.cpp in Sources */, 3FDFE56C19AF9C44009756A7 /* HostProcessPosix.cpp in Sources */, 268900B413353E5000698AC0 /* RegisterContextMacOSXFrameBackchain.cpp in Sources */, + AE44FB321BB07EBC0033EB62 /* GoParser.cpp in Sources */, 3F8169311ABB7A6D001DA9DF /* SystemInitializer.cpp in Sources */, 949EEDB21BA76731008C63CF /* NSIndexPath.cpp in Sources */, 267A47FD1B1411CC0021A5BC /* NativeRegisterContextRegisterInfo.cpp in Sources */, @@ -6638,6 +6671,7 @@ 26D5E163135BB054006EA0A7 /* OptionGroupPlatform.cpp in Sources */, 94CD131A19BA33B400DB7BED /* TypeValidator.cpp in Sources */, 26BD407F135D2AE000237D80 /* FileLineResolver.cpp in Sources */, + AE44FB311BB07EB80033EB62 /* GoLexer.cpp in Sources */, 26A7A035135E6E4200FB369E /* OptionValue.cpp in Sources */, 9A22A161135E30370024DDC3 /* EmulateInstructionARM.cpp in Sources */, AFDFDFD119E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp in Sources */, Index: source/API/SBFrame.cpp =================================================================== --- source/API/SBFrame.cpp +++ source/API/SBFrame.cpp @@ -1394,6 +1394,10 @@ lldb::DynamicValueType fetch_dynamic_value = frame->CalculateTarget()->GetPreferDynamicValue(); options.SetFetchDynamicValue (fetch_dynamic_value); options.SetUnwindOnError (true); + if (target->GetLanguage() != eLanguageTypeUnknown) + options.SetLanguage(target->GetLanguage()); + else + options.SetLanguage(frame->GetLanguage()); return EvaluateExpression (expr, options); } return result; @@ -1405,6 +1409,13 @@ SBExpressionOptions options; options.SetFetchDynamicValue (fetch_dynamic_value); options.SetUnwindOnError (true); + ExecutionContext exe_ctx(m_opaque_sp.get()); + StackFrame *frame = exe_ctx.GetFramePtr(); + Target *target = exe_ctx.GetTargetPtr(); + if (target && target->GetLanguage() != eLanguageTypeUnknown) + options.SetLanguage(target->GetLanguage()); + else if (frame) + options.SetLanguage(frame->GetLanguage()); return EvaluateExpression (expr, options); } @@ -1412,8 +1423,15 @@ SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dynamic_value, bool unwind_on_error) { SBExpressionOptions options; + ExecutionContext exe_ctx(m_opaque_sp.get()); options.SetFetchDynamicValue (fetch_dynamic_value); options.SetUnwindOnError (unwind_on_error); + StackFrame *frame = exe_ctx.GetFramePtr(); + Target *target = exe_ctx.GetTargetPtr(); + if (target && target->GetLanguage() != eLanguageTypeUnknown) + options.SetLanguage(target->GetLanguage()); + else if (frame) + options.SetLanguage(frame->GetLanguage()); return EvaluateExpression (expr, options); } Index: source/Expression/CMakeLists.txt =================================================================== --- source/Expression/CMakeLists.txt +++ source/Expression/CMakeLists.txt @@ -8,6 +8,7 @@ IRExecutionUnit.cpp IRInterpreter.cpp IRMemoryMap.cpp + LLVMUserExpression.cpp Materializer.cpp REPL.cpp UserExpression.cpp Index: source/Expression/LLVMUserExpression.cpp =================================================================== --- /dev/null +++ source/Expression/LLVMUserExpression.cpp @@ -0,0 +1,353 @@ +//===-- LLVMUserExpression.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes + +// Project includes +#include "lldb/Expression/LLVMUserExpression.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Expression/IRInterpreter.h" +#include "lldb/Expression/Materializer.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallUserExpression.h" + +using namespace lldb_private; + +LLVMUserExpression::LLVMUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type) + : UserExpression(exe_scope, expr, expr_prefix, language, desired_type), + m_stack_frame_bottom(LLDB_INVALID_ADDRESS), + m_stack_frame_top(LLDB_INVALID_ADDRESS), + m_transformed_text(), + m_execution_unit_sp(), + m_materializer_ap(), + m_jit_module_wp(), + m_enforce_valid_object(true), + m_in_cplusplus_method(false), + m_in_objectivec_method(false), + m_in_static_method(false), + m_needs_object_ptr(false), + m_const_object(false), + m_target(NULL), + m_can_interpret(false), + m_materialized_address(LLDB_INVALID_ADDRESS) +{ +} + +LLVMUserExpression::~LLVMUserExpression() +{ + if (m_target) + { + lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock()); + if (jit_module_sp) + m_target->GetImages().Remove(jit_module_sp); + } +} + +lldb::ExpressionResults +LLVMUserExpression::Execute(Stream &error_stream, ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, lldb::ExpressionVariableSP &result) +{ + // The expression log is quite verbose, and if you're just tracking the execution of the + // expression, it's quite convenient to have these logs come out with the STEP log as well. + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); + + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + { + lldb::addr_t struct_address = LLDB_INVALID_ADDRESS; + + if (!PrepareToExecuteJITExpression(error_stream, exe_ctx, struct_address)) + { + error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS; + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS; + + if (m_can_interpret) + { + llvm::Module *module = m_execution_unit_sp->GetModule(); + llvm::Function *function = m_execution_unit_sp->GetFunction(); + + if (!module || !function) + { + error_stream.Printf("Supposed to interpret, but nothing is there"); + return lldb::eExpressionSetupError; + } + + Error interpreter_error; + + std::vector args; + + if (!AddInitialArguments(exe_ctx, args, error_stream)) + { + error_stream.Printf("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + args.push_back(struct_address); + + function_stack_bottom = m_stack_frame_bottom; + function_stack_top = m_stack_frame_top; + + IRInterpreter::Interpret(*module, *function, args, *m_execution_unit_sp.get(), interpreter_error, + function_stack_bottom, function_stack_top, exe_ctx); + + if (!interpreter_error.Success()) + { + error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); + return lldb::eExpressionDiscarded; + } + } + else + { + if (!exe_ctx.HasThreadScope()) + { + error_stream.Printf("UserExpression::Execute called with no thread selected."); + return lldb::eExpressionSetupError; + } + + Address wrapper_address(m_jit_start_addr); + + std::vector args; + + if (!AddInitialArguments(exe_ctx, args, error_stream)) + { + error_stream.Printf("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + args.push_back(struct_address); + + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression(exe_ctx.GetThreadRef(), wrapper_address, + args, options, shared_ptr_to_me)); + + if (!call_plan_sp || !call_plan_sp->ValidatePlan(&error_stream)) + return lldb::eExpressionSetupError; + + ThreadPlanCallUserExpression *user_expression_plan = + static_cast(call_plan_sp.get()); + + lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); + + function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); + function_stack_top = function_stack_pointer; + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression begins --"); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); + + lldb::ExpressionResults execution_result = + exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options, error_stream); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression completed --"); + + if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) + { + const char *error_desc = NULL; + + if (call_plan_sp) + { + lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); + if (real_stop_info_sp) + error_desc = real_stop_info_sp->GetDescription(); + } + if (error_desc) + error_stream.Printf("Execution was interrupted, reason: %s.", error_desc); + else + error_stream.PutCString("Execution was interrupted."); + + if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) || + (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) + error_stream.PutCString( + "\nThe process has been returned to the state before expression evaluation."); + else + { + if (execution_result == lldb::eExpressionHitBreakpoint) + user_expression_plan->TransferExpressionOwnership(); + error_stream.PutCString( + "\nThe process has been left at the point where it was interrupted, " + "use \"thread return -x\" to return to the state before expression evaluation."); + } + + return execution_result; + } + else if (execution_result == lldb::eExpressionStoppedForDebug) + { + error_stream.PutCString( + "Execution was halted at the first instruction of the expression " + "function because \"debug\" was requested.\n" + "Use \"thread return -x\" to return to the state before expression evaluation."); + return execution_result; + } + else if (execution_result != lldb::eExpressionCompleted) + { + error_stream.Printf("Couldn't execute function; result was %s\n", + Process::ExecutionResultAsCString(execution_result)); + return execution_result; + } + } + + if (FinalizeJITExecution(error_stream, exe_ctx, result, function_stack_bottom, function_stack_top)) + { + return lldb::eExpressionCompleted; + } + else + { + return lldb::eExpressionResultUnavailable; + } + } + else + { + error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); + return lldb::eExpressionSetupError; + } +} + +bool +LLVMUserExpression::FinalizeJITExecution(Stream &error_stream, ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, lldb::addr_t function_stack_bottom, + lldb::addr_t function_stack_top) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + log->Printf("-- [UserExpression::FinalizeJITExecution] Dematerializing after execution --"); + + if (!m_dematerializer_sp) + { + error_stream.Printf("Couldn't apply expression side effects : no dematerializer is present"); + return false; + } + + Error dematerialize_error; + + m_dematerializer_sp->Dematerialize(dematerialize_error, function_stack_bottom, function_stack_top); + + if (!dematerialize_error.Success()) + { + error_stream.Printf("Couldn't apply expression side effects : %s\n", + dematerialize_error.AsCString("unknown error")); + return false; + } + + result = GetResultAfterDematerialization(exe_ctx.GetBestExecutionContextScope()); + + if (result) + result->TransferAddress(); + + m_dematerializer_sp.reset(); + + return true; +} + +bool +LLVMUserExpression::PrepareToExecuteJITExpression(Stream &error_stream, ExecutionContext &exe_ctx, + lldb::addr_t &struct_address) +{ + lldb::TargetSP target; + lldb::ProcessSP process; + lldb::StackFrameSP frame; + + if (!LockAndCheckContext(exe_ctx, target, process, frame)) + { + error_stream.Printf("The context has changed before we could JIT the expression!\n"); + return false; + } + + if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) + { + if (m_materialized_address == LLDB_INVALID_ADDRESS) + { + Error alloc_error; + + IRMemoryMap::AllocationPolicy policy = + m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror; + + m_materialized_address = m_execution_unit_sp->Malloc( + m_materializer_ap->GetStructByteSize(), m_materializer_ap->GetStructAlignment(), + lldb::ePermissionsReadable | lldb::ePermissionsWritable, policy, alloc_error); + + if (!alloc_error.Success()) + { + error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString()); + return false; + } + } + + struct_address = m_materialized_address; + + if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) + { + Error alloc_error; + + const size_t stack_frame_size = 512 * 1024; + + m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size, 8, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + IRMemoryMap::eAllocationPolicyHostOnly, alloc_error); + + m_stack_frame_top = m_stack_frame_bottom + stack_frame_size; + + if (!alloc_error.Success()) + { + error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString()); + return false; + } + } + + Error materialize_error; + + m_dematerializer_sp = + m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error); + + if (!materialize_error.Success()) + { + error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); + return false; + } + } + return true; +} + +lldb::ModuleSP +LLVMUserExpression::GetJITModule() +{ + if (m_execution_unit_sp) + return m_execution_unit_sp->GetJITModule(); + return lldb::ModuleSP(); +} Index: source/Expression/UserExpression.cpp =================================================================== --- source/Expression/UserExpression.cpp +++ source/Expression/UserExpression.cpp @@ -45,42 +45,18 @@ using namespace lldb_private; -UserExpression::UserExpression (ExecutionContextScope &exe_scope, - const char *expr, - const char *expr_prefix, - lldb::LanguageType language, - ResultType desired_type) : - Expression (exe_scope), - m_stack_frame_bottom (LLDB_INVALID_ADDRESS), - m_stack_frame_top (LLDB_INVALID_ADDRESS), - m_expr_text (expr), - m_expr_prefix (expr_prefix ? expr_prefix : ""), - m_language (language), - m_transformed_text (), - m_desired_type (desired_type), - m_execution_unit_sp(), - m_materializer_ap(), - m_jit_module_wp(), - m_enforce_valid_object (true), - m_in_cplusplus_method (false), - m_in_objectivec_method (false), - m_in_static_method(false), - m_needs_object_ptr (false), - m_const_object (false), - m_target (NULL), - m_can_interpret (false), - m_materialized_address (LLDB_INVALID_ADDRESS) +UserExpression::UserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type) + : Expression(exe_scope), + m_expr_text(expr), + m_expr_prefix(expr_prefix ? expr_prefix : ""), + m_language(language), + m_desired_type(desired_type) { } UserExpression::~UserExpression () { - if (m_target) - { - lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); - if (jit_module_sp) - m_target->GetImages().Remove(jit_module_sp); - } } void @@ -170,295 +146,6 @@ return ret; } -bool -UserExpression::PrepareToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::addr_t &struct_address) -{ - lldb::TargetSP target; - lldb::ProcessSP process; - lldb::StackFrameSP frame; - - if (!LockAndCheckContext(exe_ctx, - target, - process, - frame)) - { - error_stream.Printf("The context has changed before we could JIT the expression!\n"); - return false; - } - - if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) - { - if (m_materialized_address == LLDB_INVALID_ADDRESS) - { - Error alloc_error; - - IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror; - - m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(), - m_materializer_ap->GetStructAlignment(), - lldb::ePermissionsReadable | lldb::ePermissionsWritable, - policy, - alloc_error); - - if (!alloc_error.Success()) - { - error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString()); - return false; - } - } - - struct_address = m_materialized_address; - - if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS) - { - Error alloc_error; - - const size_t stack_frame_size = 512 * 1024; - - m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size, - 8, - lldb::ePermissionsReadable | lldb::ePermissionsWritable, - IRMemoryMap::eAllocationPolicyHostOnly, - alloc_error); - - m_stack_frame_top = m_stack_frame_bottom + stack_frame_size; - - if (!alloc_error.Success()) - { - error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString()); - return false; - } - } - - Error materialize_error; - - m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_sp, struct_address, materialize_error); - - if (!materialize_error.Success()) - { - error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); - return false; - } - } - return true; -} - -bool -UserExpression::FinalizeJITExecution (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb::ExpressionVariableSP &result, - lldb::addr_t function_stack_bottom, - lldb::addr_t function_stack_top) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - log->Printf("-- [UserExpression::FinalizeJITExecution] Dematerializing after execution --"); - - if (!m_dematerializer_sp) - { - error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present"); - return false; - } - - Error dematerialize_error; - - m_dematerializer_sp->Dematerialize(dematerialize_error, function_stack_bottom, function_stack_top); - - if (!dematerialize_error.Success()) - { - error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error")); - return false; - } - - result = GetResultAfterDematerialization(exe_ctx.GetBestExecutionContextScope()); - - if (result) - result->TransferAddress(); - - m_dematerializer_sp.reset(); - - return true; -} - -lldb::ExpressionResults -UserExpression::Execute (Stream &error_stream, - ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - lldb::UserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result) -{ - // The expression log is quite verbose, and if you're just tracking the execution of the - // expression, it's quite convenient to have these logs come out with the STEP log as well. - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); - - if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret) - { - lldb::addr_t struct_address = LLDB_INVALID_ADDRESS; - - if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address)) - { - error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); - return lldb::eExpressionSetupError; - } - - lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS; - lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS; - - if (m_can_interpret) - { - llvm::Module *module = m_execution_unit_sp->GetModule(); - llvm::Function *function = m_execution_unit_sp->GetFunction(); - - if (!module || !function) - { - error_stream.Printf("Supposed to interpret, but nothing is there"); - return lldb::eExpressionSetupError; - } - - Error interpreter_error; - - std::vector args; - - if (!AddInitialArguments(exe_ctx, args, error_stream)) - { - error_stream.Printf ("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); - return lldb::eExpressionSetupError; - } - - args.push_back(struct_address); - - function_stack_bottom = m_stack_frame_bottom; - function_stack_top = m_stack_frame_top; - - IRInterpreter::Interpret (*module, - *function, - args, - *m_execution_unit_sp.get(), - interpreter_error, - function_stack_bottom, - function_stack_top, - exe_ctx); - - if (!interpreter_error.Success()) - { - error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); - return lldb::eExpressionDiscarded; - } - } - else - { - if (!exe_ctx.HasThreadScope()) - { - error_stream.Printf("UserExpression::Execute called with no thread selected."); - return lldb::eExpressionSetupError; - } - - Address wrapper_address (m_jit_start_addr); - - std::vector args; - - if (!AddInitialArguments(exe_ctx, args, error_stream)) - { - error_stream.Printf ("Errored out in %s, couldn't AddInitialArguments", __FUNCTION__); - return lldb::eExpressionSetupError; - } - - args.push_back(struct_address); - - lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), - wrapper_address, - args, - options, - shared_ptr_to_me)); - - if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) - return lldb::eExpressionSetupError; - - ThreadPlanCallUserExpression *user_expression_plan = static_cast(call_plan_sp.get()); - - lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); - - function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); - function_stack_top = function_stack_pointer; - - if (log) - log->Printf("-- [UserExpression::Execute] Execution of expression begins --"); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); - - lldb::ExpressionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, - call_plan_sp, - options, - error_stream); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); - - if (log) - log->Printf("-- [UserExpression::Execute] Execution of expression completed --"); - - if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) - { - const char *error_desc = NULL; - - if (call_plan_sp) - { - lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); - if (real_stop_info_sp) - error_desc = real_stop_info_sp->GetDescription(); - } - if (error_desc) - error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); - else - error_stream.PutCString ("Execution was interrupted."); - - if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) - || (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) - error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation."); - else - { - if (execution_result == lldb::eExpressionHitBreakpoint) - user_expression_plan->TransferExpressionOwnership(); - error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, " - "use \"thread return -x\" to return to the state before expression evaluation."); - } - - return execution_result; - } - else if (execution_result == lldb::eExpressionStoppedForDebug) - { - error_stream.PutCString ("Execution was halted at the first instruction of the expression " - "function because \"debug\" was requested.\n" - "Use \"thread return -x\" to return to the state before expression evaluation."); - return execution_result; - } - else if (execution_result != lldb::eExpressionCompleted) - { - error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); - return execution_result; - } - } - - if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top)) - { - return lldb::eExpressionCompleted; - } - else - { - return lldb::eExpressionResultUnavailable; - } - } - else - { - error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); - return lldb::eExpressionSetupError; - } -} - lldb::ExpressionResults UserExpression::Evaluate (ExecutionContext &exe_ctx, const EvaluateExpressionOptions& options, @@ -570,8 +257,8 @@ 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(); + if (jit_module_sp_ptr) + *jit_module_sp_ptr = user_expression_sp->GetJITModule(); lldb::ExpressionVariableSP expr_result; Index: source/Plugins/ExpressionParser/CMakeLists.txt =================================================================== --- source/Plugins/ExpressionParser/CMakeLists.txt +++ source/Plugins/ExpressionParser/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(Clang) +add_subdirectory(Go) Index: source/Plugins/ExpressionParser/Clang/ClangUserExpression.h =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -27,7 +27,7 @@ #include "lldb/lldb-private.h" #include "lldb/Core/Address.h" #include "lldb/Core/ClangForward.h" -#include "lldb/Expression/UserExpression.h" +#include "lldb/Expression/LLVMUserExpression.h" #include "lldb/Expression/Materializer.h" #include "lldb/Target/ExecutionContext.h" @@ -43,7 +43,7 @@ /// the objects needed to parse and interpret or JIT an expression. It /// uses the Clang parser to produce LLVM IR from the expression. //---------------------------------------------------------------------- -class ClangUserExpression : public UserExpression +class ClangUserExpression : public LLVMUserExpression { public: enum { kDefaultTimeout = 500000u }; Index: source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -55,13 +55,10 @@ using namespace lldb_private; -ClangUserExpression::ClangUserExpression (ExecutionContextScope &exe_scope, - const char *expr, - const char *expr_prefix, - lldb::LanguageType language, - ResultType desired_type) : - UserExpression (exe_scope, expr, expr_prefix, language, desired_type), - m_type_system_helper(*m_target_wp.lock().get()) +ClangUserExpression::ClangUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type) + : LLVMUserExpression(exe_scope, expr, expr_prefix, language, desired_type), + m_type_system_helper(*m_target_wp.lock().get()) { switch (m_language) { Index: source/Plugins/ExpressionParser/Go/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/CMakeLists.txt @@ -0,0 +1,5 @@ +add_lldb_library(lldbPluginExpressionParserGo + GoLexer.cpp + GoParser.cpp + GoUserExpression.cpp + ) Index: source/Plugins/ExpressionParser/Go/GoAST.h =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoAST.h @@ -0,0 +1,3225 @@ +//===-- GoAST.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// DO NOT EDIT. +// Generated by gen_go_ast.py + +#ifndef liblldb_GoAST_h +#define liblldb_GoAST_h + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "llvm/Support/Casting.h" +#include "Plugins/ExpressionParser/Go/GoLexer.h" + +namespace lldb_private +{ + +class GoASTNode +{ + public: + typedef GoLexer::TokenType TokenType; + typedef GoLexer::Token Token; + enum ChanDir + { + eChanBidir, + eChanSend, + eChanRecv, + }; + enum NodeKind + { + eBadDecl, + eFuncDecl, + eGenDecl, + eArrayType, + eBadExpr, + eBasicLit, + eBinaryExpr, + eIdent, + eCallExpr, + eChanType, + eCompositeLit, + eEllipsis, + eFuncType, + eFuncLit, + eIndexExpr, + eInterfaceType, + eKeyValueExpr, + eMapType, + eParenExpr, + eSelectorExpr, + eSliceExpr, + eStarExpr, + eStructType, + eTypeAssertExpr, + eUnaryExpr, + eImportSpec, + eTypeSpec, + eValueSpec, + eAssignStmt, + eBadStmt, + eBlockStmt, + eBranchStmt, + eCaseClause, + eCommClause, + eDeclStmt, + eDeferStmt, + eEmptyStmt, + eExprStmt, + eForStmt, + eGoStmt, + eIfStmt, + eIncDecStmt, + eLabeledStmt, + eRangeStmt, + eReturnStmt, + eSelectStmt, + eSendStmt, + eSwitchStmt, + eTypeSwitchStmt, + eField, + eFieldList, + }; + + virtual ~GoASTNode() = default; + + NodeKind + GetKind() const + { + return m_kind; + } + + virtual const char *GetKindName() const = 0; + + template void WalkChildren(V &v); + + protected: + explicit GoASTNode(NodeKind kind) : m_kind(kind) { } + + private: + const NodeKind m_kind; + + GoASTNode(const GoASTNode &) = delete; + const GoASTNode &operator=(const GoASTNode &) = delete; +}; + + +class GoASTDecl : public GoASTNode +{ + public: + template R Visit(V *v) const; + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() >= eBadDecl && n->GetKind() <= eGenDecl; + } + + protected: + explicit GoASTDecl(NodeKind kind) : GoASTNode(kind) { } + private: + + GoASTDecl(const GoASTDecl &) = delete; + const GoASTDecl &operator=(const GoASTDecl &) = delete; +}; + +class GoASTExpr : public GoASTNode +{ + public: + template R Visit(V *v) const; + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() >= eArrayType && n->GetKind() <= eUnaryExpr; + } + + protected: + explicit GoASTExpr(NodeKind kind) : GoASTNode(kind) { } + private: + + GoASTExpr(const GoASTExpr &) = delete; + const GoASTExpr &operator=(const GoASTExpr &) = delete; +}; + +class GoASTSpec : public GoASTNode +{ + public: + template R Visit(V *v) const; + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() >= eImportSpec && n->GetKind() <= eValueSpec; + } + + protected: + explicit GoASTSpec(NodeKind kind) : GoASTNode(kind) { } + private: + + GoASTSpec(const GoASTSpec &) = delete; + const GoASTSpec &operator=(const GoASTSpec &) = delete; +}; + +class GoASTStmt : public GoASTNode +{ + public: + template R Visit(V *v) const; + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() >= eAssignStmt && n->GetKind() <= eTypeSwitchStmt; + } + + protected: + explicit GoASTStmt(NodeKind kind) : GoASTNode(kind) { } + private: + + GoASTStmt(const GoASTStmt &) = delete; + const GoASTStmt &operator=(const GoASTStmt &) = delete; +}; + + +class GoASTArrayType : public GoASTExpr +{ + public: + GoASTArrayType(GoASTExpr *len, GoASTExpr *elt) : GoASTExpr(eArrayType), m_len_up(len), m_elt_up(elt) {} + ~GoASTArrayType() override = default; + + const char * + GetKindName() const override + { + return "ArrayType"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eArrayType; + } + + const GoASTExpr * + GetLen() const + { + return m_len_up.get(); + } + void + SetLen(GoASTExpr *len) + { + m_len_up.reset(len); + } + + const GoASTExpr * + GetElt() const + { + return m_elt_up.get(); + } + void + SetElt(GoASTExpr *elt) + { + m_elt_up.reset(elt); + } + + private: + friend class GoASTNode; + std::unique_ptr m_len_up; + std::unique_ptr m_elt_up; + + GoASTArrayType(const GoASTArrayType &) = delete; + const GoASTArrayType &operator=(const GoASTArrayType &) = delete; +}; + +class GoASTAssignStmt : public GoASTStmt +{ + public: + explicit GoASTAssignStmt(bool define) : GoASTStmt(eAssignStmt), m_define(define) {} + ~GoASTAssignStmt() override = default; + + const char * + GetKindName() const override + { + return "AssignStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eAssignStmt; + } + + size_t + NumLhs() const + { + return m_lhs.size(); + } + const GoASTExpr * + GetLhs(int i) const + { + return m_lhs[i].get(); + } + void + AddLhs(GoASTExpr *lhs) + { + m_lhs.push_back(std::unique_ptr(lhs)); + } + + size_t + NumRhs() const + { + return m_rhs.size(); + } + const GoASTExpr * + GetRhs(int i) const + { + return m_rhs[i].get(); + } + void + AddRhs(GoASTExpr *rhs) + { + m_rhs.push_back(std::unique_ptr(rhs)); + } + + bool + GetDefine() const + { + return m_define; + } + void + SetDefine(bool define) + { + m_define = define; + } + + private: + friend class GoASTNode; + std::vector > m_lhs; + std::vector > m_rhs; + bool m_define; + + GoASTAssignStmt(const GoASTAssignStmt &) = delete; + const GoASTAssignStmt &operator=(const GoASTAssignStmt &) = delete; +}; + +class GoASTBadDecl : public GoASTDecl +{ + public: + GoASTBadDecl() : GoASTDecl(eBadDecl) {} + ~GoASTBadDecl() override = default; + + const char * + GetKindName() const override + { + return "BadDecl"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eBadDecl; + } + + GoASTBadDecl(const GoASTBadDecl &) = delete; + const GoASTBadDecl &operator=(const GoASTBadDecl &) = delete; +}; + +class GoASTBadExpr : public GoASTExpr +{ + public: + GoASTBadExpr() : GoASTExpr(eBadExpr) {} + ~GoASTBadExpr() override = default; + + const char * + GetKindName() const override + { + return "BadExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eBadExpr; + } + + GoASTBadExpr(const GoASTBadExpr &) = delete; + const GoASTBadExpr &operator=(const GoASTBadExpr &) = delete; +}; + +class GoASTBadStmt : public GoASTStmt +{ + public: + GoASTBadStmt() : GoASTStmt(eBadStmt) {} + ~GoASTBadStmt() override = default; + + const char * + GetKindName() const override + { + return "BadStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eBadStmt; + } + + GoASTBadStmt(const GoASTBadStmt &) = delete; + const GoASTBadStmt &operator=(const GoASTBadStmt &) = delete; +}; + +class GoASTBasicLit : public GoASTExpr +{ + public: + explicit GoASTBasicLit(Token value) : GoASTExpr(eBasicLit), m_value(value) {} + ~GoASTBasicLit() override = default; + + const char * + GetKindName() const override + { + return "BasicLit"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eBasicLit; + } + + Token + GetValue() const + { + return m_value; + } + void + SetValue(Token value) + { + m_value = value; + } + + private: + friend class GoASTNode; + Token m_value; + + GoASTBasicLit(const GoASTBasicLit &) = delete; + const GoASTBasicLit &operator=(const GoASTBasicLit &) = delete; +}; + +class GoASTBinaryExpr : public GoASTExpr +{ + public: + GoASTBinaryExpr(GoASTExpr *x, GoASTExpr *y, TokenType op) : GoASTExpr(eBinaryExpr), m_x_up(x), m_y_up(y), m_op(op) {} + ~GoASTBinaryExpr() override = default; + + const char * + GetKindName() const override + { + return "BinaryExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eBinaryExpr; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + const GoASTExpr * + GetY() const + { + return m_y_up.get(); + } + void + SetY(GoASTExpr *y) + { + m_y_up.reset(y); + } + + TokenType + GetOp() const + { + return m_op; + } + void + SetOp(TokenType op) + { + m_op = op; + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + std::unique_ptr m_y_up; + TokenType m_op; + + GoASTBinaryExpr(const GoASTBinaryExpr &) = delete; + const GoASTBinaryExpr &operator=(const GoASTBinaryExpr &) = delete; +}; + +class GoASTBlockStmt : public GoASTStmt +{ + public: + GoASTBlockStmt() : GoASTStmt(eBlockStmt) {} + ~GoASTBlockStmt() override = default; + + const char * + GetKindName() const override + { + return "BlockStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eBlockStmt; + } + + size_t + NumList() const + { + return m_list.size(); + } + const GoASTStmt * + GetList(int i) const + { + return m_list[i].get(); + } + void + AddList(GoASTStmt *list) + { + m_list.push_back(std::unique_ptr(list)); + } + + private: + friend class GoASTNode; + std::vector > m_list; + + GoASTBlockStmt(const GoASTBlockStmt &) = delete; + const GoASTBlockStmt &operator=(const GoASTBlockStmt &) = delete; +}; + +class GoASTIdent : public GoASTExpr +{ + public: + explicit GoASTIdent(Token name) : GoASTExpr(eIdent), m_name(name) {} + ~GoASTIdent() override = default; + + const char * + GetKindName() const override + { + return "Ident"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eIdent; + } + + Token + GetName() const + { + return m_name; + } + void + SetName(Token name) + { + m_name = name; + } + + private: + friend class GoASTNode; + Token m_name; + + GoASTIdent(const GoASTIdent &) = delete; + const GoASTIdent &operator=(const GoASTIdent &) = delete; +}; + +class GoASTBranchStmt : public GoASTStmt +{ + public: + GoASTBranchStmt(GoASTIdent *label, TokenType tok) : GoASTStmt(eBranchStmt), m_label_up(label), m_tok(tok) {} + ~GoASTBranchStmt() override = default; + + const char * + GetKindName() const override + { + return "BranchStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eBranchStmt; + } + + const GoASTIdent * + GetLabel() const + { + return m_label_up.get(); + } + void + SetLabel(GoASTIdent *label) + { + m_label_up.reset(label); + } + + TokenType + GetTok() const + { + return m_tok; + } + void + SetTok(TokenType tok) + { + m_tok = tok; + } + + private: + friend class GoASTNode; + std::unique_ptr m_label_up; + TokenType m_tok; + + GoASTBranchStmt(const GoASTBranchStmt &) = delete; + const GoASTBranchStmt &operator=(const GoASTBranchStmt &) = delete; +}; + +class GoASTCallExpr : public GoASTExpr +{ + public: + explicit GoASTCallExpr(bool ellipsis) : GoASTExpr(eCallExpr), m_ellipsis(ellipsis) {} + ~GoASTCallExpr() override = default; + + const char * + GetKindName() const override + { + return "CallExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eCallExpr; + } + + const GoASTExpr * + GetFun() const + { + return m_fun_up.get(); + } + void + SetFun(GoASTExpr *fun) + { + m_fun_up.reset(fun); + } + + size_t + NumArgs() const + { + return m_args.size(); + } + const GoASTExpr * + GetArgs(int i) const + { + return m_args[i].get(); + } + void + AddArgs(GoASTExpr *args) + { + m_args.push_back(std::unique_ptr(args)); + } + + bool + GetEllipsis() const + { + return m_ellipsis; + } + void + SetEllipsis(bool ellipsis) + { + m_ellipsis = ellipsis; + } + + private: + friend class GoASTNode; + std::unique_ptr m_fun_up; + std::vector > m_args; + bool m_ellipsis; + + GoASTCallExpr(const GoASTCallExpr &) = delete; + const GoASTCallExpr &operator=(const GoASTCallExpr &) = delete; +}; + +class GoASTCaseClause : public GoASTStmt +{ + public: + GoASTCaseClause() : GoASTStmt(eCaseClause) {} + ~GoASTCaseClause() override = default; + + const char * + GetKindName() const override + { + return "CaseClause"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eCaseClause; + } + + size_t + NumList() const + { + return m_list.size(); + } + const GoASTExpr * + GetList(int i) const + { + return m_list[i].get(); + } + void + AddList(GoASTExpr *list) + { + m_list.push_back(std::unique_ptr(list)); + } + + size_t + NumBody() const + { + return m_body.size(); + } + const GoASTStmt * + GetBody(int i) const + { + return m_body[i].get(); + } + void + AddBody(GoASTStmt *body) + { + m_body.push_back(std::unique_ptr(body)); + } + + private: + friend class GoASTNode; + std::vector > m_list; + std::vector > m_body; + + GoASTCaseClause(const GoASTCaseClause &) = delete; + const GoASTCaseClause &operator=(const GoASTCaseClause &) = delete; +}; + +class GoASTChanType : public GoASTExpr +{ + public: + GoASTChanType(ChanDir dir, GoASTExpr *value) : GoASTExpr(eChanType), m_dir(dir), m_value_up(value) {} + ~GoASTChanType() override = default; + + const char * + GetKindName() const override + { + return "ChanType"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eChanType; + } + + ChanDir + GetDir() const + { + return m_dir; + } + void + SetDir(ChanDir dir) + { + m_dir = dir; + } + + const GoASTExpr * + GetValue() const + { + return m_value_up.get(); + } + void + SetValue(GoASTExpr *value) + { + m_value_up.reset(value); + } + + private: + friend class GoASTNode; + ChanDir m_dir; + std::unique_ptr m_value_up; + + GoASTChanType(const GoASTChanType &) = delete; + const GoASTChanType &operator=(const GoASTChanType &) = delete; +}; + +class GoASTCommClause : public GoASTStmt +{ + public: + GoASTCommClause() : GoASTStmt(eCommClause) {} + ~GoASTCommClause() override = default; + + const char * + GetKindName() const override + { + return "CommClause"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eCommClause; + } + + const GoASTStmt * + GetComm() const + { + return m_comm_up.get(); + } + void + SetComm(GoASTStmt *comm) + { + m_comm_up.reset(comm); + } + + size_t + NumBody() const + { + return m_body.size(); + } + const GoASTStmt * + GetBody(int i) const + { + return m_body[i].get(); + } + void + AddBody(GoASTStmt *body) + { + m_body.push_back(std::unique_ptr(body)); + } + + private: + friend class GoASTNode; + std::unique_ptr m_comm_up; + std::vector > m_body; + + GoASTCommClause(const GoASTCommClause &) = delete; + const GoASTCommClause &operator=(const GoASTCommClause &) = delete; +}; + +class GoASTCompositeLit : public GoASTExpr +{ + public: + GoASTCompositeLit() : GoASTExpr(eCompositeLit) {} + ~GoASTCompositeLit() override = default; + + const char * + GetKindName() const override + { + return "CompositeLit"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eCompositeLit; + } + + const GoASTExpr * + GetType() const + { + return m_type_up.get(); + } + void + SetType(GoASTExpr *type) + { + m_type_up.reset(type); + } + + size_t + NumElts() const + { + return m_elts.size(); + } + const GoASTExpr * + GetElts(int i) const + { + return m_elts[i].get(); + } + void + AddElts(GoASTExpr *elts) + { + m_elts.push_back(std::unique_ptr(elts)); + } + + private: + friend class GoASTNode; + std::unique_ptr m_type_up; + std::vector > m_elts; + + GoASTCompositeLit(const GoASTCompositeLit &) = delete; + const GoASTCompositeLit &operator=(const GoASTCompositeLit &) = delete; +}; + +class GoASTDeclStmt : public GoASTStmt +{ + public: + explicit GoASTDeclStmt(GoASTDecl *decl) : GoASTStmt(eDeclStmt), m_decl_up(decl) {} + ~GoASTDeclStmt() override = default; + + const char * + GetKindName() const override + { + return "DeclStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eDeclStmt; + } + + const GoASTDecl * + GetDecl() const + { + return m_decl_up.get(); + } + void + SetDecl(GoASTDecl *decl) + { + m_decl_up.reset(decl); + } + + private: + friend class GoASTNode; + std::unique_ptr m_decl_up; + + GoASTDeclStmt(const GoASTDeclStmt &) = delete; + const GoASTDeclStmt &operator=(const GoASTDeclStmt &) = delete; +}; + +class GoASTDeferStmt : public GoASTStmt +{ + public: + explicit GoASTDeferStmt(GoASTCallExpr *call) : GoASTStmt(eDeferStmt), m_call_up(call) {} + ~GoASTDeferStmt() override = default; + + const char * + GetKindName() const override + { + return "DeferStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eDeferStmt; + } + + const GoASTCallExpr * + GetCall() const + { + return m_call_up.get(); + } + void + SetCall(GoASTCallExpr *call) + { + m_call_up.reset(call); + } + + private: + friend class GoASTNode; + std::unique_ptr m_call_up; + + GoASTDeferStmt(const GoASTDeferStmt &) = delete; + const GoASTDeferStmt &operator=(const GoASTDeferStmt &) = delete; +}; + +class GoASTEllipsis : public GoASTExpr +{ + public: + explicit GoASTEllipsis(GoASTExpr *elt) : GoASTExpr(eEllipsis), m_elt_up(elt) {} + ~GoASTEllipsis() override = default; + + const char * + GetKindName() const override + { + return "Ellipsis"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eEllipsis; + } + + const GoASTExpr * + GetElt() const + { + return m_elt_up.get(); + } + void + SetElt(GoASTExpr *elt) + { + m_elt_up.reset(elt); + } + + private: + friend class GoASTNode; + std::unique_ptr m_elt_up; + + GoASTEllipsis(const GoASTEllipsis &) = delete; + const GoASTEllipsis &operator=(const GoASTEllipsis &) = delete; +}; + +class GoASTEmptyStmt : public GoASTStmt +{ + public: + GoASTEmptyStmt() : GoASTStmt(eEmptyStmt) {} + ~GoASTEmptyStmt() override = default; + + const char * + GetKindName() const override + { + return "EmptyStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eEmptyStmt; + } + + GoASTEmptyStmt(const GoASTEmptyStmt &) = delete; + const GoASTEmptyStmt &operator=(const GoASTEmptyStmt &) = delete; +}; + +class GoASTExprStmt : public GoASTStmt +{ + public: + explicit GoASTExprStmt(GoASTExpr *x) : GoASTStmt(eExprStmt), m_x_up(x) {} + ~GoASTExprStmt() override = default; + + const char * + GetKindName() const override + { + return "ExprStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eExprStmt; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + + GoASTExprStmt(const GoASTExprStmt &) = delete; + const GoASTExprStmt &operator=(const GoASTExprStmt &) = delete; +}; + +class GoASTField : public GoASTNode +{ + public: + GoASTField() : GoASTNode(eField) {} + ~GoASTField() override = default; + + const char * + GetKindName() const override + { + return "Field"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eField; + } + + size_t + NumNames() const + { + return m_names.size(); + } + const GoASTIdent * + GetNames(int i) const + { + return m_names[i].get(); + } + void + AddNames(GoASTIdent *names) + { + m_names.push_back(std::unique_ptr(names)); + } + + const GoASTExpr * + GetType() const + { + return m_type_up.get(); + } + void + SetType(GoASTExpr *type) + { + m_type_up.reset(type); + } + + const GoASTBasicLit * + GetTag() const + { + return m_tag_up.get(); + } + void + SetTag(GoASTBasicLit *tag) + { + m_tag_up.reset(tag); + } + + private: + friend class GoASTNode; + std::vector > m_names; + std::unique_ptr m_type_up; + std::unique_ptr m_tag_up; + + GoASTField(const GoASTField &) = delete; + const GoASTField &operator=(const GoASTField &) = delete; +}; + +class GoASTFieldList : public GoASTNode +{ + public: + GoASTFieldList() : GoASTNode(eFieldList) {} + ~GoASTFieldList() override = default; + + const char * + GetKindName() const override + { + return "FieldList"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eFieldList; + } + + size_t + NumList() const + { + return m_list.size(); + } + const GoASTField * + GetList(int i) const + { + return m_list[i].get(); + } + void + AddList(GoASTField *list) + { + m_list.push_back(std::unique_ptr(list)); + } + + private: + friend class GoASTNode; + std::vector > m_list; + + GoASTFieldList(const GoASTFieldList &) = delete; + const GoASTFieldList &operator=(const GoASTFieldList &) = delete; +}; + +class GoASTForStmt : public GoASTStmt +{ + public: + GoASTForStmt(GoASTStmt *init, GoASTExpr *cond, GoASTStmt *post, GoASTBlockStmt *body) : GoASTStmt(eForStmt), m_init_up(init), m_cond_up(cond), m_post_up(post), m_body_up(body) {} + ~GoASTForStmt() override = default; + + const char * + GetKindName() const override + { + return "ForStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eForStmt; + } + + const GoASTStmt * + GetInit() const + { + return m_init_up.get(); + } + void + SetInit(GoASTStmt *init) + { + m_init_up.reset(init); + } + + const GoASTExpr * + GetCond() const + { + return m_cond_up.get(); + } + void + SetCond(GoASTExpr *cond) + { + m_cond_up.reset(cond); + } + + const GoASTStmt * + GetPost() const + { + return m_post_up.get(); + } + void + SetPost(GoASTStmt *post) + { + m_post_up.reset(post); + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + private: + friend class GoASTNode; + std::unique_ptr m_init_up; + std::unique_ptr m_cond_up; + std::unique_ptr m_post_up; + std::unique_ptr m_body_up; + + GoASTForStmt(const GoASTForStmt &) = delete; + const GoASTForStmt &operator=(const GoASTForStmt &) = delete; +}; + +class GoASTFuncType : public GoASTExpr +{ + public: + GoASTFuncType(GoASTFieldList *params, GoASTFieldList *results) : GoASTExpr(eFuncType), m_params_up(params), m_results_up(results) {} + ~GoASTFuncType() override = default; + + const char * + GetKindName() const override + { + return "FuncType"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eFuncType; + } + + const GoASTFieldList * + GetParams() const + { + return m_params_up.get(); + } + void + SetParams(GoASTFieldList *params) + { + m_params_up.reset(params); + } + + const GoASTFieldList * + GetResults() const + { + return m_results_up.get(); + } + void + SetResults(GoASTFieldList *results) + { + m_results_up.reset(results); + } + + private: + friend class GoASTNode; + std::unique_ptr m_params_up; + std::unique_ptr m_results_up; + + GoASTFuncType(const GoASTFuncType &) = delete; + const GoASTFuncType &operator=(const GoASTFuncType &) = delete; +}; + +class GoASTFuncDecl : public GoASTDecl +{ + public: + GoASTFuncDecl(GoASTFieldList *recv, GoASTIdent *name, GoASTFuncType *type, GoASTBlockStmt *body) : GoASTDecl(eFuncDecl), m_recv_up(recv), m_name_up(name), m_type_up(type), m_body_up(body) {} + ~GoASTFuncDecl() override = default; + + const char * + GetKindName() const override + { + return "FuncDecl"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eFuncDecl; + } + + const GoASTFieldList * + GetRecv() const + { + return m_recv_up.get(); + } + void + SetRecv(GoASTFieldList *recv) + { + m_recv_up.reset(recv); + } + + const GoASTIdent * + GetName() const + { + return m_name_up.get(); + } + void + SetName(GoASTIdent *name) + { + m_name_up.reset(name); + } + + const GoASTFuncType * + GetType() const + { + return m_type_up.get(); + } + void + SetType(GoASTFuncType *type) + { + m_type_up.reset(type); + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + private: + friend class GoASTNode; + std::unique_ptr m_recv_up; + std::unique_ptr m_name_up; + std::unique_ptr m_type_up; + std::unique_ptr m_body_up; + + GoASTFuncDecl(const GoASTFuncDecl &) = delete; + const GoASTFuncDecl &operator=(const GoASTFuncDecl &) = delete; +}; + +class GoASTFuncLit : public GoASTExpr +{ + public: + GoASTFuncLit(GoASTFuncType *type, GoASTBlockStmt *body) : GoASTExpr(eFuncLit), m_type_up(type), m_body_up(body) {} + ~GoASTFuncLit() override = default; + + const char * + GetKindName() const override + { + return "FuncLit"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eFuncLit; + } + + const GoASTFuncType * + GetType() const + { + return m_type_up.get(); + } + void + SetType(GoASTFuncType *type) + { + m_type_up.reset(type); + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + private: + friend class GoASTNode; + std::unique_ptr m_type_up; + std::unique_ptr m_body_up; + + GoASTFuncLit(const GoASTFuncLit &) = delete; + const GoASTFuncLit &operator=(const GoASTFuncLit &) = delete; +}; + +class GoASTGenDecl : public GoASTDecl +{ + public: + explicit GoASTGenDecl(TokenType tok) : GoASTDecl(eGenDecl), m_tok(tok) {} + ~GoASTGenDecl() override = default; + + const char * + GetKindName() const override + { + return "GenDecl"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eGenDecl; + } + + TokenType + GetTok() const + { + return m_tok; + } + void + SetTok(TokenType tok) + { + m_tok = tok; + } + + size_t + NumSpecs() const + { + return m_specs.size(); + } + const GoASTSpec * + GetSpecs(int i) const + { + return m_specs[i].get(); + } + void + AddSpecs(GoASTSpec *specs) + { + m_specs.push_back(std::unique_ptr(specs)); + } + + private: + friend class GoASTNode; + TokenType m_tok; + std::vector > m_specs; + + GoASTGenDecl(const GoASTGenDecl &) = delete; + const GoASTGenDecl &operator=(const GoASTGenDecl &) = delete; +}; + +class GoASTGoStmt : public GoASTStmt +{ + public: + explicit GoASTGoStmt(GoASTCallExpr *call) : GoASTStmt(eGoStmt), m_call_up(call) {} + ~GoASTGoStmt() override = default; + + const char * + GetKindName() const override + { + return "GoStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eGoStmt; + } + + const GoASTCallExpr * + GetCall() const + { + return m_call_up.get(); + } + void + SetCall(GoASTCallExpr *call) + { + m_call_up.reset(call); + } + + private: + friend class GoASTNode; + std::unique_ptr m_call_up; + + GoASTGoStmt(const GoASTGoStmt &) = delete; + const GoASTGoStmt &operator=(const GoASTGoStmt &) = delete; +}; + +class GoASTIfStmt : public GoASTStmt +{ + public: + GoASTIfStmt(GoASTStmt *init, GoASTExpr *cond, GoASTBlockStmt *body, GoASTStmt *els) : GoASTStmt(eIfStmt), m_init_up(init), m_cond_up(cond), m_body_up(body), m_els_up(els) {} + ~GoASTIfStmt() override = default; + + const char * + GetKindName() const override + { + return "IfStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eIfStmt; + } + + const GoASTStmt * + GetInit() const + { + return m_init_up.get(); + } + void + SetInit(GoASTStmt *init) + { + m_init_up.reset(init); + } + + const GoASTExpr * + GetCond() const + { + return m_cond_up.get(); + } + void + SetCond(GoASTExpr *cond) + { + m_cond_up.reset(cond); + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + const GoASTStmt * + GetEls() const + { + return m_els_up.get(); + } + void + SetEls(GoASTStmt *els) + { + m_els_up.reset(els); + } + + private: + friend class GoASTNode; + std::unique_ptr m_init_up; + std::unique_ptr m_cond_up; + std::unique_ptr m_body_up; + std::unique_ptr m_els_up; + + GoASTIfStmt(const GoASTIfStmt &) = delete; + const GoASTIfStmt &operator=(const GoASTIfStmt &) = delete; +}; + +class GoASTImportSpec : public GoASTSpec +{ + public: + GoASTImportSpec(GoASTIdent *name, GoASTBasicLit *path) : GoASTSpec(eImportSpec), m_name_up(name), m_path_up(path) {} + ~GoASTImportSpec() override = default; + + const char * + GetKindName() const override + { + return "ImportSpec"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eImportSpec; + } + + const GoASTIdent * + GetName() const + { + return m_name_up.get(); + } + void + SetName(GoASTIdent *name) + { + m_name_up.reset(name); + } + + const GoASTBasicLit * + GetPath() const + { + return m_path_up.get(); + } + void + SetPath(GoASTBasicLit *path) + { + m_path_up.reset(path); + } + + private: + friend class GoASTNode; + std::unique_ptr m_name_up; + std::unique_ptr m_path_up; + + GoASTImportSpec(const GoASTImportSpec &) = delete; + const GoASTImportSpec &operator=(const GoASTImportSpec &) = delete; +}; + +class GoASTIncDecStmt : public GoASTStmt +{ + public: + GoASTIncDecStmt(GoASTExpr *x, TokenType tok) : GoASTStmt(eIncDecStmt), m_x_up(x), m_tok(tok) {} + ~GoASTIncDecStmt() override = default; + + const char * + GetKindName() const override + { + return "IncDecStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eIncDecStmt; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + TokenType + GetTok() const + { + return m_tok; + } + void + SetTok(TokenType tok) + { + m_tok = tok; + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + TokenType m_tok; + + GoASTIncDecStmt(const GoASTIncDecStmt &) = delete; + const GoASTIncDecStmt &operator=(const GoASTIncDecStmt &) = delete; +}; + +class GoASTIndexExpr : public GoASTExpr +{ + public: + GoASTIndexExpr(GoASTExpr *x, GoASTExpr *index) : GoASTExpr(eIndexExpr), m_x_up(x), m_index_up(index) {} + ~GoASTIndexExpr() override = default; + + const char * + GetKindName() const override + { + return "IndexExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eIndexExpr; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + const GoASTExpr * + GetIndex() const + { + return m_index_up.get(); + } + void + SetIndex(GoASTExpr *index) + { + m_index_up.reset(index); + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + std::unique_ptr m_index_up; + + GoASTIndexExpr(const GoASTIndexExpr &) = delete; + const GoASTIndexExpr &operator=(const GoASTIndexExpr &) = delete; +}; + +class GoASTInterfaceType : public GoASTExpr +{ + public: + explicit GoASTInterfaceType(GoASTFieldList *methods) : GoASTExpr(eInterfaceType), m_methods_up(methods) {} + ~GoASTInterfaceType() override = default; + + const char * + GetKindName() const override + { + return "InterfaceType"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eInterfaceType; + } + + const GoASTFieldList * + GetMethods() const + { + return m_methods_up.get(); + } + void + SetMethods(GoASTFieldList *methods) + { + m_methods_up.reset(methods); + } + + private: + friend class GoASTNode; + std::unique_ptr m_methods_up; + + GoASTInterfaceType(const GoASTInterfaceType &) = delete; + const GoASTInterfaceType &operator=(const GoASTInterfaceType &) = delete; +}; + +class GoASTKeyValueExpr : public GoASTExpr +{ + public: + GoASTKeyValueExpr(GoASTExpr *key, GoASTExpr *value) : GoASTExpr(eKeyValueExpr), m_key_up(key), m_value_up(value) {} + ~GoASTKeyValueExpr() override = default; + + const char * + GetKindName() const override + { + return "KeyValueExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eKeyValueExpr; + } + + const GoASTExpr * + GetKey() const + { + return m_key_up.get(); + } + void + SetKey(GoASTExpr *key) + { + m_key_up.reset(key); + } + + const GoASTExpr * + GetValue() const + { + return m_value_up.get(); + } + void + SetValue(GoASTExpr *value) + { + m_value_up.reset(value); + } + + private: + friend class GoASTNode; + std::unique_ptr m_key_up; + std::unique_ptr m_value_up; + + GoASTKeyValueExpr(const GoASTKeyValueExpr &) = delete; + const GoASTKeyValueExpr &operator=(const GoASTKeyValueExpr &) = delete; +}; + +class GoASTLabeledStmt : public GoASTStmt +{ + public: + GoASTLabeledStmt(GoASTIdent *label, GoASTStmt *stmt) : GoASTStmt(eLabeledStmt), m_label_up(label), m_stmt_up(stmt) {} + ~GoASTLabeledStmt() override = default; + + const char * + GetKindName() const override + { + return "LabeledStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eLabeledStmt; + } + + const GoASTIdent * + GetLabel() const + { + return m_label_up.get(); + } + void + SetLabel(GoASTIdent *label) + { + m_label_up.reset(label); + } + + const GoASTStmt * + GetStmt() const + { + return m_stmt_up.get(); + } + void + SetStmt(GoASTStmt *stmt) + { + m_stmt_up.reset(stmt); + } + + private: + friend class GoASTNode; + std::unique_ptr m_label_up; + std::unique_ptr m_stmt_up; + + GoASTLabeledStmt(const GoASTLabeledStmt &) = delete; + const GoASTLabeledStmt &operator=(const GoASTLabeledStmt &) = delete; +}; + +class GoASTMapType : public GoASTExpr +{ + public: + GoASTMapType(GoASTExpr *key, GoASTExpr *value) : GoASTExpr(eMapType), m_key_up(key), m_value_up(value) {} + ~GoASTMapType() override = default; + + const char * + GetKindName() const override + { + return "MapType"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eMapType; + } + + const GoASTExpr * + GetKey() const + { + return m_key_up.get(); + } + void + SetKey(GoASTExpr *key) + { + m_key_up.reset(key); + } + + const GoASTExpr * + GetValue() const + { + return m_value_up.get(); + } + void + SetValue(GoASTExpr *value) + { + m_value_up.reset(value); + } + + private: + friend class GoASTNode; + std::unique_ptr m_key_up; + std::unique_ptr m_value_up; + + GoASTMapType(const GoASTMapType &) = delete; + const GoASTMapType &operator=(const GoASTMapType &) = delete; +}; + +class GoASTParenExpr : public GoASTExpr +{ + public: + explicit GoASTParenExpr(GoASTExpr *x) : GoASTExpr(eParenExpr), m_x_up(x) {} + ~GoASTParenExpr() override = default; + + const char * + GetKindName() const override + { + return "ParenExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eParenExpr; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + + GoASTParenExpr(const GoASTParenExpr &) = delete; + const GoASTParenExpr &operator=(const GoASTParenExpr &) = delete; +}; + +class GoASTRangeStmt : public GoASTStmt +{ + public: + GoASTRangeStmt(GoASTExpr *key, GoASTExpr *value, bool define, GoASTExpr *x, GoASTBlockStmt *body) : GoASTStmt(eRangeStmt), m_key_up(key), m_value_up(value), m_define(define), m_x_up(x), m_body_up(body) {} + ~GoASTRangeStmt() override = default; + + const char * + GetKindName() const override + { + return "RangeStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eRangeStmt; + } + + const GoASTExpr * + GetKey() const + { + return m_key_up.get(); + } + void + SetKey(GoASTExpr *key) + { + m_key_up.reset(key); + } + + const GoASTExpr * + GetValue() const + { + return m_value_up.get(); + } + void + SetValue(GoASTExpr *value) + { + m_value_up.reset(value); + } + + bool + GetDefine() const + { + return m_define; + } + void + SetDefine(bool define) + { + m_define = define; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + private: + friend class GoASTNode; + std::unique_ptr m_key_up; + std::unique_ptr m_value_up; + bool m_define; + std::unique_ptr m_x_up; + std::unique_ptr m_body_up; + + GoASTRangeStmt(const GoASTRangeStmt &) = delete; + const GoASTRangeStmt &operator=(const GoASTRangeStmt &) = delete; +}; + +class GoASTReturnStmt : public GoASTStmt +{ + public: + GoASTReturnStmt() : GoASTStmt(eReturnStmt) {} + ~GoASTReturnStmt() override = default; + + const char * + GetKindName() const override + { + return "ReturnStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eReturnStmt; + } + + size_t + NumResults() const + { + return m_results.size(); + } + const GoASTExpr * + GetResults(int i) const + { + return m_results[i].get(); + } + void + AddResults(GoASTExpr *results) + { + m_results.push_back(std::unique_ptr(results)); + } + + private: + friend class GoASTNode; + std::vector > m_results; + + GoASTReturnStmt(const GoASTReturnStmt &) = delete; + const GoASTReturnStmt &operator=(const GoASTReturnStmt &) = delete; +}; + +class GoASTSelectStmt : public GoASTStmt +{ + public: + explicit GoASTSelectStmt(GoASTBlockStmt *body) : GoASTStmt(eSelectStmt), m_body_up(body) {} + ~GoASTSelectStmt() override = default; + + const char * + GetKindName() const override + { + return "SelectStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eSelectStmt; + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + private: + friend class GoASTNode; + std::unique_ptr m_body_up; + + GoASTSelectStmt(const GoASTSelectStmt &) = delete; + const GoASTSelectStmt &operator=(const GoASTSelectStmt &) = delete; +}; + +class GoASTSelectorExpr : public GoASTExpr +{ + public: + GoASTSelectorExpr(GoASTExpr *x, GoASTIdent *sel) : GoASTExpr(eSelectorExpr), m_x_up(x), m_sel_up(sel) {} + ~GoASTSelectorExpr() override = default; + + const char * + GetKindName() const override + { + return "SelectorExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eSelectorExpr; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + const GoASTIdent * + GetSel() const + { + return m_sel_up.get(); + } + void + SetSel(GoASTIdent *sel) + { + m_sel_up.reset(sel); + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + std::unique_ptr m_sel_up; + + GoASTSelectorExpr(const GoASTSelectorExpr &) = delete; + const GoASTSelectorExpr &operator=(const GoASTSelectorExpr &) = delete; +}; + +class GoASTSendStmt : public GoASTStmt +{ + public: + GoASTSendStmt(GoASTExpr *chan, GoASTExpr *value) : GoASTStmt(eSendStmt), m_chan_up(chan), m_value_up(value) {} + ~GoASTSendStmt() override = default; + + const char * + GetKindName() const override + { + return "SendStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eSendStmt; + } + + const GoASTExpr * + GetChan() const + { + return m_chan_up.get(); + } + void + SetChan(GoASTExpr *chan) + { + m_chan_up.reset(chan); + } + + const GoASTExpr * + GetValue() const + { + return m_value_up.get(); + } + void + SetValue(GoASTExpr *value) + { + m_value_up.reset(value); + } + + private: + friend class GoASTNode; + std::unique_ptr m_chan_up; + std::unique_ptr m_value_up; + + GoASTSendStmt(const GoASTSendStmt &) = delete; + const GoASTSendStmt &operator=(const GoASTSendStmt &) = delete; +}; + +class GoASTSliceExpr : public GoASTExpr +{ + public: + GoASTSliceExpr(GoASTExpr *x, GoASTExpr *low, GoASTExpr *high, GoASTExpr *max, bool slice3) : GoASTExpr(eSliceExpr), m_x_up(x), m_low_up(low), m_high_up(high), m_max_up(max), m_slice3(slice3) {} + ~GoASTSliceExpr() override = default; + + const char * + GetKindName() const override + { + return "SliceExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eSliceExpr; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + const GoASTExpr * + GetLow() const + { + return m_low_up.get(); + } + void + SetLow(GoASTExpr *low) + { + m_low_up.reset(low); + } + + const GoASTExpr * + GetHigh() const + { + return m_high_up.get(); + } + void + SetHigh(GoASTExpr *high) + { + m_high_up.reset(high); + } + + const GoASTExpr * + GetMax() const + { + return m_max_up.get(); + } + void + SetMax(GoASTExpr *max) + { + m_max_up.reset(max); + } + + bool + GetSlice3() const + { + return m_slice3; + } + void + SetSlice3(bool slice3) + { + m_slice3 = slice3; + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + std::unique_ptr m_low_up; + std::unique_ptr m_high_up; + std::unique_ptr m_max_up; + bool m_slice3; + + GoASTSliceExpr(const GoASTSliceExpr &) = delete; + const GoASTSliceExpr &operator=(const GoASTSliceExpr &) = delete; +}; + +class GoASTStarExpr : public GoASTExpr +{ + public: + explicit GoASTStarExpr(GoASTExpr *x) : GoASTExpr(eStarExpr), m_x_up(x) {} + ~GoASTStarExpr() override = default; + + const char * + GetKindName() const override + { + return "StarExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eStarExpr; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + + GoASTStarExpr(const GoASTStarExpr &) = delete; + const GoASTStarExpr &operator=(const GoASTStarExpr &) = delete; +}; + +class GoASTStructType : public GoASTExpr +{ + public: + explicit GoASTStructType(GoASTFieldList *fields) : GoASTExpr(eStructType), m_fields_up(fields) {} + ~GoASTStructType() override = default; + + const char * + GetKindName() const override + { + return "StructType"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eStructType; + } + + const GoASTFieldList * + GetFields() const + { + return m_fields_up.get(); + } + void + SetFields(GoASTFieldList *fields) + { + m_fields_up.reset(fields); + } + + private: + friend class GoASTNode; + std::unique_ptr m_fields_up; + + GoASTStructType(const GoASTStructType &) = delete; + const GoASTStructType &operator=(const GoASTStructType &) = delete; +}; + +class GoASTSwitchStmt : public GoASTStmt +{ + public: + GoASTSwitchStmt(GoASTStmt *init, GoASTExpr *tag, GoASTBlockStmt *body) : GoASTStmt(eSwitchStmt), m_init_up(init), m_tag_up(tag), m_body_up(body) {} + ~GoASTSwitchStmt() override = default; + + const char * + GetKindName() const override + { + return "SwitchStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eSwitchStmt; + } + + const GoASTStmt * + GetInit() const + { + return m_init_up.get(); + } + void + SetInit(GoASTStmt *init) + { + m_init_up.reset(init); + } + + const GoASTExpr * + GetTag() const + { + return m_tag_up.get(); + } + void + SetTag(GoASTExpr *tag) + { + m_tag_up.reset(tag); + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + private: + friend class GoASTNode; + std::unique_ptr m_init_up; + std::unique_ptr m_tag_up; + std::unique_ptr m_body_up; + + GoASTSwitchStmt(const GoASTSwitchStmt &) = delete; + const GoASTSwitchStmt &operator=(const GoASTSwitchStmt &) = delete; +}; + +class GoASTTypeAssertExpr : public GoASTExpr +{ + public: + GoASTTypeAssertExpr(GoASTExpr *x, GoASTExpr *type) : GoASTExpr(eTypeAssertExpr), m_x_up(x), m_type_up(type) {} + ~GoASTTypeAssertExpr() override = default; + + const char * + GetKindName() const override + { + return "TypeAssertExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eTypeAssertExpr; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + const GoASTExpr * + GetType() const + { + return m_type_up.get(); + } + void + SetType(GoASTExpr *type) + { + m_type_up.reset(type); + } + + private: + friend class GoASTNode; + std::unique_ptr m_x_up; + std::unique_ptr m_type_up; + + GoASTTypeAssertExpr(const GoASTTypeAssertExpr &) = delete; + const GoASTTypeAssertExpr &operator=(const GoASTTypeAssertExpr &) = delete; +}; + +class GoASTTypeSpec : public GoASTSpec +{ + public: + GoASTTypeSpec(GoASTIdent *name, GoASTExpr *type) : GoASTSpec(eTypeSpec), m_name_up(name), m_type_up(type) {} + ~GoASTTypeSpec() override = default; + + const char * + GetKindName() const override + { + return "TypeSpec"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eTypeSpec; + } + + const GoASTIdent * + GetName() const + { + return m_name_up.get(); + } + void + SetName(GoASTIdent *name) + { + m_name_up.reset(name); + } + + const GoASTExpr * + GetType() const + { + return m_type_up.get(); + } + void + SetType(GoASTExpr *type) + { + m_type_up.reset(type); + } + + private: + friend class GoASTNode; + std::unique_ptr m_name_up; + std::unique_ptr m_type_up; + + GoASTTypeSpec(const GoASTTypeSpec &) = delete; + const GoASTTypeSpec &operator=(const GoASTTypeSpec &) = delete; +}; + +class GoASTTypeSwitchStmt : public GoASTStmt +{ + public: + GoASTTypeSwitchStmt(GoASTStmt *init, GoASTStmt *assign, GoASTBlockStmt *body) : GoASTStmt(eTypeSwitchStmt), m_init_up(init), m_assign_up(assign), m_body_up(body) {} + ~GoASTTypeSwitchStmt() override = default; + + const char * + GetKindName() const override + { + return "TypeSwitchStmt"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eTypeSwitchStmt; + } + + const GoASTStmt * + GetInit() const + { + return m_init_up.get(); + } + void + SetInit(GoASTStmt *init) + { + m_init_up.reset(init); + } + + const GoASTStmt * + GetAssign() const + { + return m_assign_up.get(); + } + void + SetAssign(GoASTStmt *assign) + { + m_assign_up.reset(assign); + } + + const GoASTBlockStmt * + GetBody() const + { + return m_body_up.get(); + } + void + SetBody(GoASTBlockStmt *body) + { + m_body_up.reset(body); + } + + private: + friend class GoASTNode; + std::unique_ptr m_init_up; + std::unique_ptr m_assign_up; + std::unique_ptr m_body_up; + + GoASTTypeSwitchStmt(const GoASTTypeSwitchStmt &) = delete; + const GoASTTypeSwitchStmt &operator=(const GoASTTypeSwitchStmt &) = delete; +}; + +class GoASTUnaryExpr : public GoASTExpr +{ + public: + GoASTUnaryExpr(TokenType op, GoASTExpr *x) : GoASTExpr(eUnaryExpr), m_op(op), m_x_up(x) {} + ~GoASTUnaryExpr() override = default; + + const char * + GetKindName() const override + { + return "UnaryExpr"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eUnaryExpr; + } + + TokenType + GetOp() const + { + return m_op; + } + void + SetOp(TokenType op) + { + m_op = op; + } + + const GoASTExpr * + GetX() const + { + return m_x_up.get(); + } + void + SetX(GoASTExpr *x) + { + m_x_up.reset(x); + } + + private: + friend class GoASTNode; + TokenType m_op; + std::unique_ptr m_x_up; + + GoASTUnaryExpr(const GoASTUnaryExpr &) = delete; + const GoASTUnaryExpr &operator=(const GoASTUnaryExpr &) = delete; +}; + +class GoASTValueSpec : public GoASTSpec +{ + public: + GoASTValueSpec() : GoASTSpec(eValueSpec) {} + ~GoASTValueSpec() override = default; + + const char * + GetKindName() const override + { + return "ValueSpec"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == eValueSpec; + } + + size_t + NumNames() const + { + return m_names.size(); + } + const GoASTIdent * + GetNames(int i) const + { + return m_names[i].get(); + } + void + AddNames(GoASTIdent *names) + { + m_names.push_back(std::unique_ptr(names)); + } + + const GoASTExpr * + GetType() const + { + return m_type_up.get(); + } + void + SetType(GoASTExpr *type) + { + m_type_up.reset(type); + } + + size_t + NumValues() const + { + return m_values.size(); + } + const GoASTExpr * + GetValues(int i) const + { + return m_values[i].get(); + } + void + AddValues(GoASTExpr *values) + { + m_values.push_back(std::unique_ptr(values)); + } + + private: + friend class GoASTNode; + std::vector > m_names; + std::unique_ptr m_type_up; + std::vector > m_values; + + GoASTValueSpec(const GoASTValueSpec &) = delete; + const GoASTValueSpec &operator=(const GoASTValueSpec &) = delete; +}; + + +template +R GoASTDecl::Visit(V* v) const +{ + switch(GetKind()) + { + case eBadDecl: + return v->VisitBadDecl(llvm::cast(this)); + case eFuncDecl: + return v->VisitFuncDecl(llvm::cast(this)); + case eGenDecl: + return v->VisitGenDecl(llvm::cast(this)); + default: + assert(false && "Invalid kind"); + } +} + +template +R GoASTExpr::Visit(V* v) const +{ + switch(GetKind()) + { + case eArrayType: + return v->VisitArrayType(llvm::cast(this)); + case eBadExpr: + return v->VisitBadExpr(llvm::cast(this)); + case eBasicLit: + return v->VisitBasicLit(llvm::cast(this)); + case eBinaryExpr: + return v->VisitBinaryExpr(llvm::cast(this)); + case eIdent: + return v->VisitIdent(llvm::cast(this)); + case eCallExpr: + return v->VisitCallExpr(llvm::cast(this)); + case eChanType: + return v->VisitChanType(llvm::cast(this)); + case eCompositeLit: + return v->VisitCompositeLit(llvm::cast(this)); + case eEllipsis: + return v->VisitEllipsis(llvm::cast(this)); + case eFuncType: + return v->VisitFuncType(llvm::cast(this)); + case eFuncLit: + return v->VisitFuncLit(llvm::cast(this)); + case eIndexExpr: + return v->VisitIndexExpr(llvm::cast(this)); + case eInterfaceType: + return v->VisitInterfaceType(llvm::cast(this)); + case eKeyValueExpr: + return v->VisitKeyValueExpr(llvm::cast(this)); + case eMapType: + return v->VisitMapType(llvm::cast(this)); + case eParenExpr: + return v->VisitParenExpr(llvm::cast(this)); + case eSelectorExpr: + return v->VisitSelectorExpr(llvm::cast(this)); + case eSliceExpr: + return v->VisitSliceExpr(llvm::cast(this)); + case eStarExpr: + return v->VisitStarExpr(llvm::cast(this)); + case eStructType: + return v->VisitStructType(llvm::cast(this)); + case eTypeAssertExpr: + return v->VisitTypeAssertExpr(llvm::cast(this)); + case eUnaryExpr: + return v->VisitUnaryExpr(llvm::cast(this)); + default: + assert(false && "Invalid kind"); + } +} + +template +R GoASTSpec::Visit(V* v) const +{ + switch(GetKind()) + { + case eImportSpec: + return v->VisitImportSpec(llvm::cast(this)); + case eTypeSpec: + return v->VisitTypeSpec(llvm::cast(this)); + case eValueSpec: + return v->VisitValueSpec(llvm::cast(this)); + default: + assert(false && "Invalid kind"); + } +} + +template +R GoASTStmt::Visit(V* v) const +{ + switch(GetKind()) + { + case eAssignStmt: + return v->VisitAssignStmt(llvm::cast(this)); + case eBadStmt: + return v->VisitBadStmt(llvm::cast(this)); + case eBlockStmt: + return v->VisitBlockStmt(llvm::cast(this)); + case eBranchStmt: + return v->VisitBranchStmt(llvm::cast(this)); + case eCaseClause: + return v->VisitCaseClause(llvm::cast(this)); + case eCommClause: + return v->VisitCommClause(llvm::cast(this)); + case eDeclStmt: + return v->VisitDeclStmt(llvm::cast(this)); + case eDeferStmt: + return v->VisitDeferStmt(llvm::cast(this)); + case eEmptyStmt: + return v->VisitEmptyStmt(llvm::cast(this)); + case eExprStmt: + return v->VisitExprStmt(llvm::cast(this)); + case eForStmt: + return v->VisitForStmt(llvm::cast(this)); + case eGoStmt: + return v->VisitGoStmt(llvm::cast(this)); + case eIfStmt: + return v->VisitIfStmt(llvm::cast(this)); + case eIncDecStmt: + return v->VisitIncDecStmt(llvm::cast(this)); + case eLabeledStmt: + return v->VisitLabeledStmt(llvm::cast(this)); + case eRangeStmt: + return v->VisitRangeStmt(llvm::cast(this)); + case eReturnStmt: + return v->VisitReturnStmt(llvm::cast(this)); + case eSelectStmt: + return v->VisitSelectStmt(llvm::cast(this)); + case eSendStmt: + return v->VisitSendStmt(llvm::cast(this)); + case eSwitchStmt: + return v->VisitSwitchStmt(llvm::cast(this)); + case eTypeSwitchStmt: + return v->VisitTypeSwitchStmt(llvm::cast(this)); + default: + assert(false && "Invalid kind"); + } +} + +template +void GoASTNode::WalkChildren(V &v) +{ + switch (m_kind) + { + + + case eArrayType: + { + GoASTArrayType *n = llvm::cast(this); + (void)n; + v(n->m_len_up.get()); + v(n->m_elt_up.get()); + return; + } + case eAssignStmt: + { + GoASTAssignStmt *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_lhs) { v(e.get()); } + for (auto& e : n->m_rhs) { v(e.get()); } + return; + } + case eBasicLit: + { + GoASTBasicLit *n = llvm::cast(this); + (void)n; + return; + } + case eBinaryExpr: + { + GoASTBinaryExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + v(n->m_y_up.get()); + return; + } + case eBlockStmt: + { + GoASTBlockStmt *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_list) { v(e.get()); } + return; + } + case eIdent: + { + GoASTIdent *n = llvm::cast(this); + (void)n; + return; + } + case eBranchStmt: + { + GoASTBranchStmt *n = llvm::cast(this); + (void)n; + v(n->m_label_up.get()); + return; + } + case eCallExpr: + { + GoASTCallExpr *n = llvm::cast(this); + (void)n; + v(n->m_fun_up.get()); + for (auto& e : n->m_args) { v(e.get()); } + return; + } + case eCaseClause: + { + GoASTCaseClause *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_list) { v(e.get()); } + for (auto& e : n->m_body) { v(e.get()); } + return; + } + case eChanType: + { + GoASTChanType *n = llvm::cast(this); + (void)n; + v(n->m_value_up.get()); + return; + } + case eCommClause: + { + GoASTCommClause *n = llvm::cast(this); + (void)n; + v(n->m_comm_up.get()); + for (auto& e : n->m_body) { v(e.get()); } + return; + } + case eCompositeLit: + { + GoASTCompositeLit *n = llvm::cast(this); + (void)n; + v(n->m_type_up.get()); + for (auto& e : n->m_elts) { v(e.get()); } + return; + } + case eDeclStmt: + { + GoASTDeclStmt *n = llvm::cast(this); + (void)n; + v(n->m_decl_up.get()); + return; + } + case eDeferStmt: + { + GoASTDeferStmt *n = llvm::cast(this); + (void)n; + v(n->m_call_up.get()); + return; + } + case eEllipsis: + { + GoASTEllipsis *n = llvm::cast(this); + (void)n; + v(n->m_elt_up.get()); + return; + } + case eExprStmt: + { + GoASTExprStmt *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + return; + } + case eField: + { + GoASTField *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_names) { v(e.get()); } + v(n->m_type_up.get()); + v(n->m_tag_up.get()); + return; + } + case eFieldList: + { + GoASTFieldList *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_list) { v(e.get()); } + return; + } + case eForStmt: + { + GoASTForStmt *n = llvm::cast(this); + (void)n; + v(n->m_init_up.get()); + v(n->m_cond_up.get()); + v(n->m_post_up.get()); + v(n->m_body_up.get()); + return; + } + case eFuncType: + { + GoASTFuncType *n = llvm::cast(this); + (void)n; + v(n->m_params_up.get()); + v(n->m_results_up.get()); + return; + } + case eFuncDecl: + { + GoASTFuncDecl *n = llvm::cast(this); + (void)n; + v(n->m_recv_up.get()); + v(n->m_name_up.get()); + v(n->m_type_up.get()); + v(n->m_body_up.get()); + return; + } + case eFuncLit: + { + GoASTFuncLit *n = llvm::cast(this); + (void)n; + v(n->m_type_up.get()); + v(n->m_body_up.get()); + return; + } + case eGenDecl: + { + GoASTGenDecl *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_specs) { v(e.get()); } + return; + } + case eGoStmt: + { + GoASTGoStmt *n = llvm::cast(this); + (void)n; + v(n->m_call_up.get()); + return; + } + case eIfStmt: + { + GoASTIfStmt *n = llvm::cast(this); + (void)n; + v(n->m_init_up.get()); + v(n->m_cond_up.get()); + v(n->m_body_up.get()); + v(n->m_els_up.get()); + return; + } + case eImportSpec: + { + GoASTImportSpec *n = llvm::cast(this); + (void)n; + v(n->m_name_up.get()); + v(n->m_path_up.get()); + return; + } + case eIncDecStmt: + { + GoASTIncDecStmt *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + return; + } + case eIndexExpr: + { + GoASTIndexExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + v(n->m_index_up.get()); + return; + } + case eInterfaceType: + { + GoASTInterfaceType *n = llvm::cast(this); + (void)n; + v(n->m_methods_up.get()); + return; + } + case eKeyValueExpr: + { + GoASTKeyValueExpr *n = llvm::cast(this); + (void)n; + v(n->m_key_up.get()); + v(n->m_value_up.get()); + return; + } + case eLabeledStmt: + { + GoASTLabeledStmt *n = llvm::cast(this); + (void)n; + v(n->m_label_up.get()); + v(n->m_stmt_up.get()); + return; + } + case eMapType: + { + GoASTMapType *n = llvm::cast(this); + (void)n; + v(n->m_key_up.get()); + v(n->m_value_up.get()); + return; + } + case eParenExpr: + { + GoASTParenExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + return; + } + case eRangeStmt: + { + GoASTRangeStmt *n = llvm::cast(this); + (void)n; + v(n->m_key_up.get()); + v(n->m_value_up.get()); + v(n->m_x_up.get()); + v(n->m_body_up.get()); + return; + } + case eReturnStmt: + { + GoASTReturnStmt *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_results) { v(e.get()); } + return; + } + case eSelectStmt: + { + GoASTSelectStmt *n = llvm::cast(this); + (void)n; + v(n->m_body_up.get()); + return; + } + case eSelectorExpr: + { + GoASTSelectorExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + v(n->m_sel_up.get()); + return; + } + case eSendStmt: + { + GoASTSendStmt *n = llvm::cast(this); + (void)n; + v(n->m_chan_up.get()); + v(n->m_value_up.get()); + return; + } + case eSliceExpr: + { + GoASTSliceExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + v(n->m_low_up.get()); + v(n->m_high_up.get()); + v(n->m_max_up.get()); + return; + } + case eStarExpr: + { + GoASTStarExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + return; + } + case eStructType: + { + GoASTStructType *n = llvm::cast(this); + (void)n; + v(n->m_fields_up.get()); + return; + } + case eSwitchStmt: + { + GoASTSwitchStmt *n = llvm::cast(this); + (void)n; + v(n->m_init_up.get()); + v(n->m_tag_up.get()); + v(n->m_body_up.get()); + return; + } + case eTypeAssertExpr: + { + GoASTTypeAssertExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + v(n->m_type_up.get()); + return; + } + case eTypeSpec: + { + GoASTTypeSpec *n = llvm::cast(this); + (void)n; + v(n->m_name_up.get()); + v(n->m_type_up.get()); + return; + } + case eTypeSwitchStmt: + { + GoASTTypeSwitchStmt *n = llvm::cast(this); + (void)n; + v(n->m_init_up.get()); + v(n->m_assign_up.get()); + v(n->m_body_up.get()); + return; + } + case eUnaryExpr: + { + GoASTUnaryExpr *n = llvm::cast(this); + (void)n; + v(n->m_x_up.get()); + return; + } + case eValueSpec: + { + GoASTValueSpec *n = llvm::cast(this); + (void)n; + for (auto& e : n->m_names) { v(e.get()); } + v(n->m_type_up.get()); + for (auto& e : n->m_values) { v(e.get()); } + return; + } + + case eEmptyStmt: + case eBadDecl: + case eBadExpr: + case eBadStmt: + break; + } +} + +} // namespace lldb_private + +#endif + Index: source/Plugins/ExpressionParser/Go/GoLexer.h =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoLexer.h @@ -0,0 +1,201 @@ +//===-- GoLexer.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GoLexer_h +#define liblldb_GoLexer_h + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" + +namespace lldb_private +{ + +class GoLexer +{ + public: + explicit GoLexer(const char *src); + + enum TokenType + { + TOK_EOF, + TOK_INVALID, + TOK_IDENTIFIER, + LIT_INTEGER, + LIT_FLOAT, + LIT_IMAGINARY, + LIT_RUNE, + LIT_STRING, + KEYWORD_BREAK, + KEYWORD_DEFAULT, + KEYWORD_FUNC, + KEYWORD_INTERFACE, + KEYWORD_SELECT, + KEYWORD_CASE, + KEYWORD_DEFER, + KEYWORD_GO, + KEYWORD_MAP, + KEYWORD_STRUCT, + KEYWORD_CHAN, + KEYWORD_ELSE, + KEYWORD_GOTO, + KEYWORD_PACKAGE, + KEYWORD_SWITCH, + KEYWORD_CONST, + KEYWORD_FALLTHROUGH, + KEYWORD_IF, + KEYWORD_RANGE, + KEYWORD_TYPE, + KEYWORD_CONTINUE, + KEYWORD_FOR, + KEYWORD_IMPORT, + KEYWORD_RETURN, + KEYWORD_VAR, + OP_PLUS, + OP_MINUS, + OP_STAR, + OP_SLASH, + OP_PERCENT, + OP_AMP, + OP_PIPE, + OP_CARET, + OP_LSHIFT, + OP_RSHIFT, + OP_AMP_CARET, + OP_PLUS_EQ, + OP_MINUS_EQ, + OP_STAR_EQ, + OP_SLASH_EQ, + OP_PERCENT_EQ, + OP_AMP_EQ, + OP_PIPE_EQ, + OP_CARET_EQ, + OP_LSHIFT_EQ, + OP_RSHIFT_EQ, + OP_AMP_CARET_EQ, + OP_AMP_AMP, + OP_PIPE_PIPE, + OP_LT_MINUS, + OP_PLUS_PLUS, + OP_MINUS_MINUS, + OP_EQ_EQ, + OP_LT, + OP_GT, + OP_EQ, + OP_BANG, + OP_BANG_EQ, + OP_LT_EQ, + OP_GT_EQ, + OP_COLON_EQ, + OP_DOTS, + OP_LPAREN, + OP_LBRACK, + OP_LBRACE, + OP_COMMA, + OP_DOT, + OP_RPAREN, + OP_RBRACK, + OP_RBRACE, + OP_SEMICOLON, + OP_COLON, + }; + + struct Token + { + explicit Token(TokenType t, llvm::StringRef text) : m_type(t), m_value(text) {} + TokenType m_type; + llvm::StringRef m_value; + }; + + const Token &Lex(); + + size_t + BytesRemaining() const + { + return m_end - m_src; + } + llvm::StringRef + GetString(int len) const + { + return llvm::StringRef(m_src, len); + } + + static TokenType LookupKeyword(llvm::StringRef id); + static llvm::StringRef LookupToken(TokenType t); + + private: + bool + IsDecimal(char c) + { + return c >= '0' && c <= '9'; + } + bool + IsHexChar(char c) + { + if (c >= '0' && c <= '9') + return true; + if (c >= 'A' && c <= 'F') + return true; + if (c >= 'a' && c <= 'f') + return true; + return false; + } + bool + IsLetterOrDigit(char c) + { + if (c >= 'a' && c <= 'z') + return true; + if (c >= 'A' && c <= 'Z') + return true; + if (c == '_') + return true; + if (c >= '0' && c <= '9') + return true; + // Treat all non-ascii chars as letters for simplicity. + return 0 != (c & 0x80); + } + bool + IsWhitespace(char c) + { + switch (c) + { + case ' ': + case '\t': + case '\r': + return true; + } + return false; + } + + bool SkipWhitespace(); + bool SkipComment(); + + TokenType InternalLex(bool newline); + + TokenType DoOperator(); + + TokenType DoIdent(); + + TokenType DoNumber(); + + TokenType DoRune(); + + TokenType DoString(); + + static llvm::StringMap *InitKeywords(); + + static llvm::StringMap *m_keywords; + + const char *m_src; + const char *m_end; + Token m_last_token; +}; + +} // namespace lldb_private + +#endif Index: source/Plugins/ExpressionParser/Go/GoLexer.cpp =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoLexer.cpp @@ -0,0 +1,402 @@ +//===-- GoLexer.cpp ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include + +#include "GoLexer.h" + +using namespace lldb_private; + +llvm::StringMap *GoLexer::m_keywords; + +GoLexer::GoLexer(const char *src) : m_src(src), m_end(src + strlen(src)), m_last_token(TOK_INVALID, "") +{ +} + +bool +GoLexer::SkipWhitespace() +{ + bool saw_newline = false; + for (; m_src < m_end; ++m_src) + { + if (*m_src == '\n') + saw_newline = true; + if (*m_src == '/' && !SkipComment()) + return saw_newline; + else if (!IsWhitespace(*m_src)) + return saw_newline; + } + return saw_newline; +} + +bool +GoLexer::SkipComment() +{ + if (m_src[0] == '/' && m_src[1] == '/') + { + for (const char *c = m_src + 2; c < m_end; ++c) + { + if (*c == '\n') + { + m_src = c - 1; + return true; + } + } + return true; + } + else if (m_src[0] == '/' && m_src[1] == '*') + { + for (const char *c = m_src + 2; c < m_end; ++c) + { + if (c[0] == '*' && c[1] == '/') + { + m_src = c + 1; + return true; + } + } + } + return false; +} + +const GoLexer::Token & +GoLexer::Lex() +{ + bool newline = SkipWhitespace(); + const char *start = m_src; + m_last_token.m_type = InternalLex(newline); + m_last_token.m_value = llvm::StringRef(start, m_src - start); + return m_last_token; +} + +GoLexer::TokenType +GoLexer::InternalLex(bool newline) +{ + if (m_src >= m_end) + { + return TOK_EOF; + } + if (newline) + { + switch (m_last_token.m_type) + { + case TOK_IDENTIFIER: + case LIT_FLOAT: + case LIT_IMAGINARY: + case LIT_INTEGER: + case LIT_RUNE: + case LIT_STRING: + case KEYWORD_BREAK: + case KEYWORD_CONTINUE: + case KEYWORD_FALLTHROUGH: + case KEYWORD_RETURN: + case OP_PLUS_PLUS: + case OP_MINUS_MINUS: + case OP_RPAREN: + case OP_RBRACK: + case OP_RBRACE: + return OP_SEMICOLON; + default: + break; + } + } + char c = *m_src; + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return DoNumber(); + case '+': + case '-': + case '*': + case '/': + case '%': + case '&': + case '|': + case '^': + case '<': + case '>': + case '!': + case ':': + case ';': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case ',': + case '=': + return DoOperator(); + case '.': + if (IsDecimal(m_src[1])) + return DoNumber(); + return DoOperator(); + case '$': + // For lldb persistent vars. + return DoIdent(); + case '"': + case '`': + return DoString(); + case '\'': + return DoRune(); + default: + break; + } + if (IsLetterOrDigit(c)) + return DoIdent(); + ++m_src; + return TOK_INVALID; +} + +GoLexer::TokenType +GoLexer::DoOperator() +{ + TokenType t = TOK_INVALID; + if (m_end - m_src > 2) + { + t = LookupKeyword(llvm::StringRef(m_src, 3)); + if (t != TOK_INVALID) + m_src += 3; + } + if (t == TOK_INVALID && m_end - m_src > 1) + { + t = LookupKeyword(llvm::StringRef(m_src, 2)); + if (t != TOK_INVALID) + m_src += 2; + } + if (t == TOK_INVALID) + { + t = LookupKeyword(llvm::StringRef(m_src, 1)); + ++m_src; + } + return t; +} + +GoLexer::TokenType +GoLexer::DoIdent() +{ + const char *start = m_src++; + while (m_src < m_end && IsLetterOrDigit(*m_src)) + { + ++m_src; + } + TokenType kw = LookupKeyword(llvm::StringRef(start, m_src - start)); + if (kw != TOK_INVALID) + return kw; + return TOK_IDENTIFIER; +} + +GoLexer::TokenType +GoLexer::DoNumber() +{ + if (m_src[0] == '0' && (m_src[1] == 'x' || m_src[1] == 'X')) + { + m_src += 2; + while (IsHexChar(*m_src)) + ++m_src; + return LIT_INTEGER; + } + bool dot_ok = true; + bool e_ok = true; + while (true) + { + while (IsDecimal(*m_src)) + ++m_src; + switch (*m_src) + { + case 'i': + ++m_src; + return LIT_IMAGINARY; + case '.': + if (!dot_ok) + return LIT_FLOAT; + ++m_src; + dot_ok = false; + break; + case 'e': + case 'E': + if (!e_ok) + return LIT_FLOAT; + dot_ok = e_ok = false; + ++m_src; + if (*m_src == '+' || *m_src == '-') + ++m_src; + break; + default: + if (dot_ok) + return LIT_INTEGER; + return LIT_FLOAT; + } + } +} + +GoLexer::TokenType +GoLexer::DoRune() +{ + while (++m_src < m_end) + { + switch (*m_src) + { + case '\'': + ++m_src; + return LIT_RUNE; + case '\n': + return TOK_INVALID; + case '\\': + if (m_src[1] == '\n') + return TOK_INVALID; + ++m_src; + } + } + return TOK_INVALID; +} + +GoLexer::TokenType +GoLexer::DoString() +{ + if (*m_src == '`') + { + while (++m_src < m_end) + { + if (*m_src == '`') + { + ++m_src; + return LIT_STRING; + } + } + return TOK_INVALID; + } + while (++m_src < m_end) + { + switch (*m_src) + { + case '"': + ++m_src; + return LIT_STRING; + case '\n': + return TOK_INVALID; + case '\\': + if (m_src[1] == '\n') + return TOK_INVALID; + ++m_src; + } + } + return TOK_INVALID; +} + +GoLexer::TokenType +GoLexer::LookupKeyword(llvm::StringRef id) +{ + if (m_keywords == nullptr) + m_keywords = InitKeywords(); + const auto &it = m_keywords->find(id); + if (it == m_keywords->end()) + return TOK_INVALID; + return it->second; +} + +llvm::StringRef +GoLexer::LookupToken(TokenType t) +{ + if (m_keywords == nullptr) + m_keywords = InitKeywords(); + for (const auto &e : *m_keywords) + { + if (e.getValue() == t) + return e.getKey(); + } + return ""; +} + +llvm::StringMap * +GoLexer::InitKeywords() +{ + auto &result = *new llvm::StringMap(128); + result["break"] = KEYWORD_BREAK; + result["default"] = KEYWORD_DEFAULT; + result["func"] = KEYWORD_FUNC; + result["interface"] = KEYWORD_INTERFACE; + result["select"] = KEYWORD_SELECT; + result["case"] = KEYWORD_CASE; + result["defer"] = KEYWORD_DEFER; + result["go"] = KEYWORD_GO; + result["map"] = KEYWORD_MAP; + result["struct"] = KEYWORD_STRUCT; + result["chan"] = KEYWORD_CHAN; + result["else"] = KEYWORD_ELSE; + result["goto"] = KEYWORD_GOTO; + result["package"] = KEYWORD_PACKAGE; + result["switch"] = KEYWORD_SWITCH; + result["const"] = KEYWORD_CONST; + result["fallthrough"] = KEYWORD_FALLTHROUGH; + result["if"] = KEYWORD_IF; + result["range"] = KEYWORD_RANGE; + result["type"] = KEYWORD_TYPE; + result["continue"] = KEYWORD_CONTINUE; + result["for"] = KEYWORD_FOR; + result["import"] = KEYWORD_IMPORT; + result["return"] = KEYWORD_RETURN; + result["var"] = KEYWORD_VAR; + result["+"] = OP_PLUS; + result["-"] = OP_MINUS; + result["*"] = OP_STAR; + result["/"] = OP_SLASH; + result["%"] = OP_PERCENT; + result["&"] = OP_AMP; + result["|"] = OP_PIPE; + result["^"] = OP_CARET; + result["<<"] = OP_LSHIFT; + result[">>"] = OP_RSHIFT; + result["&^"] = OP_AMP_CARET; + result["+="] = OP_PLUS_EQ; + result["-="] = OP_MINUS_EQ; + result["*="] = OP_STAR_EQ; + result["/="] = OP_SLASH_EQ; + result["%="] = OP_PERCENT_EQ; + result["&="] = OP_AMP_EQ; + result["|="] = OP_PIPE_EQ; + result["^="] = OP_CARET_EQ; + result["<<="] = OP_LSHIFT_EQ; + result[">>="] = OP_RSHIFT_EQ; + result["&^="] = OP_AMP_CARET_EQ; + result["&&"] = OP_AMP_AMP; + result["||"] = OP_PIPE_PIPE; + result["<-"] = OP_LT_MINUS; + result["++"] = OP_PLUS_PLUS; + result["--"] = OP_MINUS_MINUS; + result["=="] = OP_EQ_EQ; + result["<"] = OP_LT; + result[">"] = OP_GT; + result["="] = OP_EQ; + result["!"] = OP_BANG; + result["!="] = OP_BANG_EQ; + result["<="] = OP_LT_EQ; + result[">="] = OP_GT_EQ; + result[":="] = OP_COLON_EQ; + result["..."] = OP_DOTS; + result["("] = OP_LPAREN; + result["["] = OP_LBRACK; + result["{"] = OP_LBRACE; + result[","] = OP_COMMA; + result["."] = OP_DOT; + result[")"] = OP_RPAREN; + result["]"] = OP_RBRACK; + result["}"] = OP_RBRACE; + result[";"] = OP_SEMICOLON; + result[":"] = OP_COLON; + return &result; +} Index: source/Plugins/ExpressionParser/Go/GoParser.h =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoParser.h @@ -0,0 +1,165 @@ +//===-- GoParser.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GoParser_h +#define liblldb_GoParser_h + +#include "lldb/lldb-private.h" +#include "Plugins/ExpressionParser/Go/GoAST.h" +#include "Plugins/ExpressionParser/Go/GoLexer.h" + +namespace lldb_private +{ +class GoParser +{ + public: + explicit GoParser(const char *src); + + GoASTStmt *Statement(); + + GoASTStmt *GoStmt(); + GoASTStmt *ReturnStmt(); + GoASTStmt *BranchStmt(); + GoASTStmt *EmptyStmt(); + GoASTStmt *ExpressionStmt(GoASTExpr *e); + GoASTStmt *IncDecStmt(GoASTExpr *e); + GoASTStmt *Assignment(GoASTExpr *e); + GoASTBlockStmt *Block(); + + GoASTExpr *MoreExpressionList(); // ["," Expression] + GoASTIdent *MoreIdentifierList(); // ["," Identifier] + + GoASTExpr *Expression(); + GoASTExpr *UnaryExpr(); + GoASTExpr *OrExpr(); + GoASTExpr *AndExpr(); + GoASTExpr *RelExpr(); + GoASTExpr *AddExpr(); + GoASTExpr *MulExpr(); + GoASTExpr *PrimaryExpr(); + GoASTExpr *Operand(); + GoASTExpr *Conversion(); + + GoASTExpr *Selector(GoASTExpr *e); + GoASTExpr *IndexOrSlice(GoASTExpr *e); + GoASTExpr *TypeAssertion(GoASTExpr *e); + GoASTExpr *Arguments(GoASTExpr *e); + + GoASTExpr *Type(); + GoASTExpr *Type2(); + GoASTExpr *ArrayOrSliceType(bool allowEllipsis); + GoASTExpr *StructType(); + GoASTExpr *FunctionType(); + GoASTExpr *InterfaceType(); + GoASTExpr *MapType(); + GoASTExpr *ChanType(); + GoASTExpr *ChanType2(); + + GoASTExpr *Name(); + GoASTExpr *QualifiedIdent(GoASTIdent *p); + GoASTIdent *Identifier(); + + GoASTField *FieldDecl(); + GoASTExpr *AnonymousFieldType(); + GoASTExpr *FieldNamesAndType(GoASTField *f); + + GoASTFieldList *Params(); + GoASTField *ParamDecl(); + GoASTExpr *ParamType(); + GoASTFuncType *Signature(); + GoASTExpr *CompositeLit(); + GoASTExpr *FunctionLit(); + GoASTExpr *Element(); + GoASTCompositeLit *LiteralValue(); + + bool + Failed() const + { + return m_failed; + } + bool + AtEOF() const + { + return m_lexer.BytesRemaining() == 0 && m_pos == m_tokens.size(); + } + + void GetError(Error &error); + + private: + class Rule; + friend class Rule; + + std::nullptr_t + syntaxerror() + { + m_failed = true; + return nullptr; + } + GoLexer::Token & + next() + { + if (m_pos >= m_tokens.size()) + { + if (m_pos != 0 && + (m_tokens.back().m_type == GoLexer::TOK_EOF || m_tokens.back().m_type == GoLexer::TOK_INVALID)) + return m_tokens.back(); + m_pos = m_tokens.size(); + m_tokens.push_back(m_lexer.Lex()); + } + return m_tokens[m_pos++]; + } + GoLexer::TokenType + peek() + { + GoLexer::Token &tok = next(); + --m_pos; + return tok.m_type; + } + GoLexer::Token * + match(GoLexer::TokenType t) + { + GoLexer::Token &tok = next(); + if (tok.m_type == t) + return &tok; + --m_pos; + m_last_tok = t; + return nullptr; + } + GoLexer::Token * + mustMatch(GoLexer::TokenType t) + { + GoLexer::Token *tok = match(t); + if (tok) + return tok; + return syntaxerror(); + } + bool Semicolon(); + + GoASTStmt * + FinishStmt(GoASTStmt *s) + { + if (!Semicolon()) + m_failed = true; + return s; + } + + llvm::StringRef CopyString(llvm::StringRef s); + + GoLexer m_lexer; + std::vector m_tokens; + size_t m_pos; + llvm::StringRef m_error; + llvm::StringRef m_last; + GoLexer::TokenType m_last_tok; + llvm::StringMap m_strings; + bool m_failed; +}; +} + +#endif Index: source/Plugins/ExpressionParser/Go/GoParser.cpp =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoParser.cpp @@ -0,0 +1,1035 @@ +//===-- GoParser.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include + +#include "GoParser.h" + +#include "lldb/Core/Error.h" +#include "llvm/ADT/SmallString.h" +#include "Plugins/ExpressionParser/Go/GoAST.h" + +using namespace lldb_private; +using namespace lldb; + +namespace +{ +llvm::StringRef +DescribeToken(GoLexer::TokenType t) +{ + switch (t) + { + case GoLexer::TOK_EOF: + return ""; + case GoLexer::TOK_IDENTIFIER: + return "identifier"; + case GoLexer::LIT_FLOAT: + return "float"; + case GoLexer::LIT_IMAGINARY: + return "imaginary"; + case GoLexer::LIT_INTEGER: + return "integer"; + case GoLexer::LIT_RUNE: + return "rune"; + case GoLexer::LIT_STRING: + return "string"; + default: + return GoLexer::LookupToken(t); + } +} +} // namespace + +class GoParser::Rule +{ + public: + Rule(llvm::StringRef name, GoParser *p) : m_name(name), m_parser(p), m_pos(p->m_pos) {} + + std::nullptr_t + error() + { + if (!m_parser->m_failed) + { + // Set m_error in case this is the top level. + if (m_parser->m_last_tok == GoLexer::TOK_INVALID) + m_parser->m_error = m_parser->m_last; + else + m_parser->m_error = DescribeToken(m_parser->m_last_tok); + // And set m_last in case it isn't. + m_parser->m_last = m_name; + m_parser->m_last_tok = GoLexer::TOK_INVALID; + m_parser->m_pos = m_pos; + } + return nullptr; + } + + private: + llvm::StringRef m_name; + GoParser *m_parser; + size_t m_pos; +}; + +GoParser::GoParser(const char *src) : m_lexer(src), m_pos(0), m_failed(false) +{ +} + +GoASTStmt * +GoParser::Statement() +{ + Rule r("Statement", this); + GoLexer::TokenType t = peek(); + GoASTStmt *ret = nullptr; + switch (t) + { + case GoLexer::TOK_EOF: + case GoLexer::OP_SEMICOLON: + case GoLexer::OP_RPAREN: + case GoLexer::OP_RBRACE: + case GoLexer::TOK_INVALID: + return EmptyStmt(); + case GoLexer::OP_LBRACE: + return Block(); + + /* TODO: + case GoLexer::KEYWORD_GO: + return GoStmt(); + case GoLexer::KEYWORD_RETURN: + return ReturnStmt(); + case GoLexer::KEYWORD_BREAK: + case GoLexer::KEYWORD_CONTINUE: + case GoLexer::KEYWORD_GOTO: + case GoLexer::KEYWORD_FALLTHROUGH: + return BranchStmt(); + case GoLexer::KEYWORD_IF: + return IfStmt(); + case GoLexer::KEYWORD_SWITCH: + return SwitchStmt(); + case GoLexer::KEYWORD_SELECT: + return SelectStmt(); + case GoLexer::KEYWORD_FOR: + return ForStmt(); + case GoLexer::KEYWORD_DEFER: + return DeferStmt(); + case GoLexer::KEYWORD_CONST: + case GoLexer::KEYWORD_TYPE: + case GoLexer::KEYWORD_VAR: + return DeclStmt(); + case GoLexer::TOK_IDENTIFIER: + if ((ret = LabeledStmt()) || + (ret = ShortVarDecl())) + { + return ret; + } +*/ + default: + break; + } + GoASTExpr *expr = Expression(); + if (expr == nullptr) + return r.error(); + if (/*(ret = SendStmt(expr)) ||*/ + (ret = IncDecStmt(expr)) || (ret = Assignment(expr)) || (ret = ExpressionStmt(expr))) + { + return ret; + } + delete expr; + return r.error(); +} + +GoASTStmt * +GoParser::ExpressionStmt(GoASTExpr *e) +{ + if (Semicolon()) + return new GoASTExprStmt(e); + return nullptr; +} + +GoASTStmt * +GoParser::IncDecStmt(GoASTExpr *e) +{ + Rule r("IncDecStmt", this); + if (match(GoLexer::OP_PLUS_PLUS)) + return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_PLUS_PLUS) : r.error(); + if (match(GoLexer::OP_MINUS_MINUS)) + return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_MINUS_MINUS) : r.error(); + return nullptr; +} + +GoASTStmt * +GoParser::Assignment(lldb_private::GoASTExpr *e) +{ + Rule r("Assignment", this); + std::vector> lhs; + for (GoASTExpr *l = MoreExpressionList(); l; l = MoreExpressionList()) + lhs.push_back(std::unique_ptr(l)); + switch (peek()) + { + case GoLexer::OP_EQ: + case GoLexer::OP_PLUS_EQ: + case GoLexer::OP_MINUS_EQ: + case GoLexer::OP_PIPE_EQ: + case GoLexer::OP_CARET_EQ: + case GoLexer::OP_STAR_EQ: + case GoLexer::OP_SLASH_EQ: + case GoLexer::OP_PERCENT_EQ: + case GoLexer::OP_LSHIFT_EQ: + case GoLexer::OP_RSHIFT_EQ: + case GoLexer::OP_AMP_EQ: + case GoLexer::OP_AMP_CARET_EQ: + break; + default: + return r.error(); + } + // We don't want to own e until we know this is an assignment. + std::unique_ptr stmt(new GoASTAssignStmt(false)); + stmt->AddLhs(e); + for (auto &l : lhs) + stmt->AddLhs(l.release()); + for (GoASTExpr *r = Expression(); r; r = MoreExpressionList()) + stmt->AddRhs(r); + if (!Semicolon() || stmt->NumRhs() == 0) + return new GoASTBadStmt; + return stmt.release(); +} + +GoASTStmt * +GoParser::EmptyStmt() +{ + if (match(GoLexer::TOK_EOF)) + return nullptr; + if (Semicolon()) + return new GoASTEmptyStmt; + return nullptr; +} + +GoASTStmt * +GoParser::GoStmt() +{ + if (match(GoLexer::KEYWORD_GO)) + { + if (GoASTCallExpr *e = llvm::dyn_cast_or_null(Expression())) + { + return FinishStmt(new GoASTGoStmt(e)); + } + m_last = "call expression"; + m_failed = true; + return new GoASTBadStmt(); + } + return nullptr; +} + +GoASTStmt * +GoParser::ReturnStmt() +{ + if (match(GoLexer::KEYWORD_RETURN)) + { + std::unique_ptr r(new GoASTReturnStmt()); + for (GoASTExpr *e = Expression(); e; e = MoreExpressionList()) + r->AddResults(e); + return FinishStmt(r.release()); + } + return nullptr; +} + +GoASTStmt * +GoParser::BranchStmt() +{ + GoLexer::Token *tok; + if ((tok = match(GoLexer::KEYWORD_BREAK)) || (tok = match(GoLexer::KEYWORD_CONTINUE)) || + (tok = match(GoLexer::KEYWORD_GOTO))) + { + auto *e = Identifier(); + if (tok->m_type == GoLexer::KEYWORD_GOTO && !e) + return syntaxerror(); + return FinishStmt(new GoASTBranchStmt(e, tok->m_type)); + } + if ((tok = match(GoLexer::KEYWORD_FALLTHROUGH))) + return FinishStmt(new GoASTBranchStmt(nullptr, tok->m_type)); + + return nullptr; +} + +GoASTIdent * +GoParser::Identifier() +{ + if (auto *tok = match(GoLexer::TOK_IDENTIFIER)) + return new GoASTIdent(*tok); + return nullptr; +} + +GoASTExpr * +GoParser::MoreExpressionList() +{ + if (match(GoLexer::OP_COMMA)) + { + auto *e = Expression(); + if (!e) + return syntaxerror(); + return e; + } + return nullptr; +} + +GoASTIdent * +GoParser::MoreIdentifierList() +{ + if (match(GoLexer::OP_COMMA)) + { + auto *i = Identifier(); + if (!i) + return syntaxerror(); + return i; + } + return nullptr; +} + +GoASTExpr * +GoParser::Expression() +{ + Rule r("Expression", this); + if (GoASTExpr *ret = OrExpr()) + return ret; + return r.error(); +} + +GoASTExpr * +GoParser::UnaryExpr() +{ + switch (peek()) + { + case GoLexer::OP_PLUS: + case GoLexer::OP_MINUS: + case GoLexer::OP_BANG: + case GoLexer::OP_CARET: + case GoLexer::OP_STAR: + case GoLexer::OP_AMP: + case GoLexer::OP_LT_MINUS: + { + const GoLexer::Token t = next(); + if (GoASTExpr *e = UnaryExpr()) + { + if (t.m_type == GoLexer::OP_STAR) + return new GoASTStarExpr(e); + else + return new GoASTUnaryExpr(t.m_type, e); + } + return syntaxerror(); + } + default: + return PrimaryExpr(); + } +} + +GoASTExpr * +GoParser::OrExpr() +{ + std::unique_ptr l(AndExpr()); + if (l) + { + while (match(GoLexer::OP_PIPE_PIPE)) + { + GoASTExpr *r = AndExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_PIPE_PIPE)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::AndExpr() +{ + std::unique_ptr l(RelExpr()); + if (l) + { + while (match(GoLexer::OP_AMP_AMP)) + { + GoASTExpr *r = RelExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_AMP_AMP)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::RelExpr() +{ + std::unique_ptr l(AddExpr()); + if (l) + { + for (GoLexer::Token *t; (t = match(GoLexer::OP_EQ_EQ)) || (t = match(GoLexer::OP_BANG_EQ)) || + (t = match(GoLexer::OP_LT)) || (t = match(GoLexer::OP_LT_EQ)) || + (t = match(GoLexer::OP_GT)) || (t = match(GoLexer::OP_GT_EQ));) + { + GoLexer::TokenType op = t->m_type; + GoASTExpr *r = AddExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, op)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::AddExpr() +{ + std::unique_ptr l(MulExpr()); + if (l) + { + for (GoLexer::Token *t; (t = match(GoLexer::OP_PLUS)) || (t = match(GoLexer::OP_MINUS)) || + (t = match(GoLexer::OP_PIPE)) || (t = match(GoLexer::OP_CARET));) + { + GoLexer::TokenType op = t->m_type; + GoASTExpr *r = MulExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, op)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::MulExpr() +{ + std::unique_ptr l(UnaryExpr()); + if (l) + { + for (GoLexer::Token *t; (t = match(GoLexer::OP_STAR)) || (t = match(GoLexer::OP_SLASH)) || + (t = match(GoLexer::OP_PERCENT)) || (t = match(GoLexer::OP_LSHIFT)) || + (t = match(GoLexer::OP_RSHIFT)) || (t = match(GoLexer::OP_AMP)) || + (t = match(GoLexer::OP_AMP_CARET));) + { + GoLexer::TokenType op = t->m_type; + GoASTExpr *r = UnaryExpr(); + if (r) + l.reset(new GoASTBinaryExpr(l.release(), r, op)); + else + return syntaxerror(); + } + return l.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::PrimaryExpr() +{ + GoASTExpr *l; + GoASTExpr *r; + (l = Conversion()) || (l = Operand()); + if (!l) + return nullptr; + while ((r = Selector(l)) || (r = IndexOrSlice(l)) || (r = TypeAssertion(l)) || (r = Arguments(l))) + { + l = r; + } + return l; +} + +GoASTExpr * +GoParser::Operand() +{ + GoLexer::Token *lit; + if ((lit = match(GoLexer::LIT_INTEGER)) || (lit = match(GoLexer::LIT_FLOAT)) || + (lit = match(GoLexer::LIT_IMAGINARY)) || (lit = match(GoLexer::LIT_RUNE)) || (lit = match(GoLexer::LIT_STRING))) + return new GoASTBasicLit(*lit); + if (match(GoLexer::OP_LPAREN)) + { + GoASTExpr *e; + if (!((e = Expression()) && match(GoLexer::OP_RPAREN))) + return syntaxerror(); + return e; + } + // MethodExpr should be handled by Selector + if (GoASTExpr *e = CompositeLit()) + return e; + if (GoASTExpr *n = Name()) + return n; + return FunctionLit(); +} + +GoASTExpr * +GoParser::FunctionLit() +{ + if (!match(GoLexer::KEYWORD_FUNC)) + return nullptr; + auto *sig = Signature(); + if (!sig) + return syntaxerror(); + auto *body = Block(); + if (!body) + { + delete sig; + return syntaxerror(); + } + return new GoASTFuncLit(sig, body); +} + +GoASTBlockStmt * +GoParser::Block() +{ + if (!match(GoLexer::OP_LBRACE)) + return nullptr; + std::unique_ptr block(new GoASTBlockStmt); + for (auto *s = Statement(); s; s = Statement()) + block->AddList(s); + if (!match(GoLexer::OP_RBRACE)) + return syntaxerror(); + return block.release(); +} + +GoASTExpr * +GoParser::CompositeLit() +{ + Rule r("CompositeLit", this); + GoASTExpr *type; + (type = StructType()) || (type = ArrayOrSliceType(true)) || (type = MapType()) || (type = Name()); + if (!type) + return r.error(); + GoASTCompositeLit *lit = LiteralValue(); + if (!lit) + return r.error(); + lit->SetType(type); + return lit; +} + +GoASTCompositeLit * +GoParser::LiteralValue() +{ + if (!match(GoLexer::OP_LBRACE)) + return nullptr; + std::unique_ptr lit(new GoASTCompositeLit); + for (GoASTExpr *e = Element(); e; e = Element()) + { + lit->AddElts(e); + if (!match(GoLexer::OP_COMMA)) + break; + } + if (!mustMatch(GoLexer::OP_RBRACE)) + return nullptr; + return lit.release(); +} + +GoASTExpr * +GoParser::Element() +{ + GoASTExpr *key; + if (!((key = Expression()) || (key = LiteralValue()))) + return nullptr; + if (!match(GoLexer::OP_COLON)) + return key; + GoASTExpr *value; + if ((value = Expression()) || (value = LiteralValue())) + return new GoASTKeyValueExpr(key, value); + delete key; + return syntaxerror(); +} + +GoASTExpr * +GoParser::Selector(GoASTExpr *e) +{ + Rule r("Selector", this); + if (match(GoLexer::OP_DOT)) + { + if (auto *name = Identifier()) + return new GoASTSelectorExpr(e, name); + } + return r.error(); +} + +GoASTExpr * +GoParser::IndexOrSlice(GoASTExpr *e) +{ + Rule r("IndexOrSlice", this); + if (match(GoLexer::OP_LBRACK)) + { + std::unique_ptr i1(Expression()), i2, i3; + bool slice = false; + if (match(GoLexer::OP_COLON)) + { + slice = true; + i2.reset(Expression()); + if (i2 && match(GoLexer::OP_COLON)) + { + i3.reset(Expression()); + if (!i3) + return syntaxerror(); + } + } + if (!(slice || i1)) + return syntaxerror(); + if (!mustMatch(GoLexer::OP_RBRACK)) + return nullptr; + if (slice) + { + bool slice3 = i3.get(); + return new GoASTSliceExpr(e, i1.release(), i2.release(), i3.release(), slice3); + } + return new GoASTIndexExpr(e, i1.release()); + } + return r.error(); +} + +GoASTExpr * +GoParser::TypeAssertion(GoASTExpr *e) +{ + Rule r("TypeAssertion", this); + if (match(GoLexer::OP_DOT) && match(GoLexer::OP_LPAREN)) + { + if (auto *t = Type()) + { + if (!mustMatch(GoLexer::OP_RPAREN)) + return nullptr; + return new GoASTTypeAssertExpr(e, t); + } + return syntaxerror(); + } + return r.error(); +} + +GoASTExpr * +GoParser::Arguments(GoASTExpr *e) +{ + if (match(GoLexer::OP_LPAREN)) + { + std::unique_ptr call(new GoASTCallExpr(false)); + GoASTExpr *arg; + // ( ExpressionList | Type [ "," ExpressionList ] ) + for ((arg = Expression()) || (arg = Type()); arg; arg = MoreExpressionList()) + { + call->AddArgs(arg); + } + if (match(GoLexer::OP_DOTS)) + call->SetEllipsis(true); + + // Eat trailing comma + match(GoLexer::OP_COMMA); + + if (!mustMatch(GoLexer::OP_RPAREN)) + return nullptr; + call->SetFun(e); + return call.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::Conversion() +{ + Rule r("Conversion", this); + if (GoASTExpr *t = Type2()) + { + if (match(GoLexer::OP_LPAREN)) + { + GoASTExpr *v = Expression(); + if (!v) + return syntaxerror(); + match(GoLexer::OP_COMMA); + if (!mustMatch(GoLexer::OP_RPAREN)) + return r.error(); + GoASTCallExpr *call = new GoASTCallExpr(false); + call->SetFun(t); + call->AddArgs(v); + return call; + } + } + return r.error(); +} + +GoASTExpr * +GoParser::Type2() +{ + switch (peek()) + { + case GoLexer::OP_LBRACK: + return ArrayOrSliceType(false); + case GoLexer::KEYWORD_STRUCT: + return StructType(); + case GoLexer::KEYWORD_FUNC: + return FunctionType(); + case GoLexer::KEYWORD_INTERFACE: + return InterfaceType(); + case GoLexer::KEYWORD_MAP: + return MapType(); + case GoLexer::KEYWORD_CHAN: + return ChanType2(); + default: + return nullptr; + } +} + +GoASTExpr * +GoParser::ArrayOrSliceType(bool allowEllipsis) +{ + Rule r("ArrayType", this); + if (match(GoLexer::OP_LBRACK)) + { + std::unique_ptr len; + if (allowEllipsis && match(GoLexer::OP_DOTS)) + { + len.reset(new GoASTEllipsis(nullptr)); + } + else + { + len.reset(Expression()); + } + + if (!match(GoLexer::OP_RBRACK)) + return r.error(); + GoASTExpr *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTArrayType(len.release(), elem); + } + return r.error(); +} + +GoASTExpr * +GoParser::StructType() +{ + if (!(match(GoLexer::KEYWORD_STRUCT) && mustMatch(GoLexer::OP_LBRACE))) + return nullptr; + std::unique_ptr fields(new GoASTFieldList); + while (auto *field = FieldDecl()) + fields->AddList(field); + if (!mustMatch(GoLexer::OP_RBRACE)) + return nullptr; + return new GoASTStructType(fields.release()); +} + +GoASTField * +GoParser::FieldDecl() +{ + std::unique_ptr f(new GoASTField); + GoASTExpr *t = FieldNamesAndType(f.get()); + if (!t) + t = AnonymousFieldType(); + if (!t) + return nullptr; + + if (auto *tok = match(GoLexer::LIT_STRING)) + f->SetTag(new GoASTBasicLit(*tok)); + if (!Semicolon()) + return syntaxerror(); + return f.release(); +} + +GoASTExpr * +GoParser::FieldNamesAndType(GoASTField *field) +{ + Rule r("FieldNames", this); + for (auto *id = Identifier(); id; id = MoreIdentifierList()) + field->AddNames(id); + if (m_failed) + return nullptr; + GoASTExpr *t = Type(); + if (t) + return t; + return r.error(); +} + +GoASTExpr * +GoParser::AnonymousFieldType() +{ + bool pointer = match(GoLexer::OP_STAR); + GoASTExpr *t = Type(); + if (!t) + return nullptr; + if (pointer) + return new GoASTStarExpr(t); + return t; +} + +GoASTExpr * +GoParser::FunctionType() +{ + if (!match(GoLexer::KEYWORD_FUNC)) + return nullptr; + return Signature(); +} + +GoASTFuncType * +GoParser::Signature() +{ + auto *params = Params(); + if (!params) + return syntaxerror(); + auto *result = Params(); + if (!result) + { + if (auto *t = Type()) + { + result = new GoASTFieldList; + auto *f = new GoASTField; + f->SetType(t); + result->AddList(f); + } + } + return new GoASTFuncType(params, result); +} + +GoASTFieldList * +GoParser::Params() +{ + if (!match(GoLexer::OP_LPAREN)) + return nullptr; + std::unique_ptr l(new GoASTFieldList); + while (GoASTField *p = ParamDecl()) + { + l->AddList(p); + if (!match(GoLexer::OP_COMMA)) + break; + } + if (!mustMatch(GoLexer::OP_RPAREN)) + return nullptr; + return l.release(); +} + +GoASTField * +GoParser::ParamDecl() +{ + std::unique_ptr field(new GoASTField); + GoASTIdent *id = Identifier(); + if (id) + { + // Try `IdentifierList [ "..." ] Type`. + // If that fails, backtrack and try `[ "..." ] Type`. + Rule r("NamedParam", this); + for (; id; id = MoreIdentifierList()) + field->AddNames(id); + GoASTExpr *t = ParamType(); + if (t) + { + field->SetType(t); + return field.release(); + } + field.reset(new GoASTField); + r.error(); + } + GoASTExpr *t = ParamType(); + if (t) + { + field->SetType(t); + return field.release(); + } + return nullptr; +} + +GoASTExpr * +GoParser::ParamType() +{ + bool dots = match(GoLexer::OP_DOTS); + GoASTExpr *t = Type(); + if (!dots) + return t; + if (!t) + return syntaxerror(); + return new GoASTEllipsis(t); +} + +GoASTExpr * +GoParser::InterfaceType() +{ + if (!match(GoLexer::KEYWORD_INTERFACE) || !mustMatch(GoLexer::OP_LBRACE)) + return nullptr; + std::unique_ptr methods(new GoASTFieldList); + while (true) + { + Rule r("MethodSpec", this); + // ( identifier Signature | TypeName ) ; + std::unique_ptr id(Identifier()); + if (!id) + break; + GoASTExpr *type = Signature(); + if (!type) + { + r.error(); + id.reset(); + type = Name(); + } + if (!Semicolon()) + return syntaxerror(); + auto *f = new GoASTField; + if (id) + f->AddNames(id.release()); + f->SetType(type); + methods->AddList(f); + } + if (!mustMatch(GoLexer::OP_RBRACE)) + return nullptr; + return new GoASTInterfaceType(methods.release()); +} + +GoASTExpr * +GoParser::MapType() +{ + if (!(match(GoLexer::KEYWORD_MAP) && mustMatch(GoLexer::OP_LBRACK))) + return nullptr; + std::unique_ptr key(Type()); + if (!key) + return syntaxerror(); + if (!mustMatch(GoLexer::OP_RBRACK)) + return nullptr; + auto *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTMapType(key.release(), elem); +} + +GoASTExpr * +GoParser::ChanType() +{ + Rule r("chan", this); + if (match(GoLexer::OP_LT_MINUS)) + { + if (match(GoLexer::KEYWORD_CHAN)) + { + auto *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTChanType(GoASTNode::eChanRecv, elem); + } + return r.error(); + } + return ChanType2(); +} + +GoASTExpr * +GoParser::ChanType2() +{ + if (!match(GoLexer::KEYWORD_CHAN)) + return nullptr; + auto dir = GoASTNode::eChanBidir; + if (match(GoLexer::OP_LT_MINUS)) + dir = GoASTNode::eChanSend; + auto *elem = Type(); + if (!elem) + return syntaxerror(); + return new GoASTChanType(dir, elem); +} + +GoASTExpr * +GoParser::Type() +{ + if (GoASTExpr *t = Type2()) + return t; + if (GoASTExpr *t = Name()) + return t; + if (GoASTExpr *t = ChanType()) + return t; + if (match(GoLexer::OP_STAR)) + { + GoASTExpr *t = Type(); + if (!t) + return syntaxerror(); + return new GoASTStarExpr(t); + } + if (match(GoLexer::OP_LPAREN)) + { + std::unique_ptr t(Type()); + if (!t || !match(GoLexer::OP_RPAREN)) + return syntaxerror(); + return t.release(); + } + return nullptr; +} + +bool +GoParser::Semicolon() +{ + if (match(GoLexer::OP_SEMICOLON)) + return true; + switch (peek()) + { + case GoLexer::OP_RPAREN: + case GoLexer::OP_RBRACE: + case GoLexer::TOK_EOF: + return true; + default: + return false; + } +} + +GoASTExpr * +GoParser::Name() +{ + if (auto *id = Identifier()) + { + if (GoASTExpr *qual = QualifiedIdent(id)) + return qual; + return id; + } + return nullptr; +} + +GoASTExpr * +GoParser::QualifiedIdent(lldb_private::GoASTIdent *p) +{ + Rule r("QualifiedIdent", this); + llvm::SmallString<32> path(p->GetName().m_value); + GoLexer::Token *next; + bool have_slashes = false; + // LLDB extension: support full/package/path.name + while (match(GoLexer::OP_SLASH) && (next = match(GoLexer::TOK_IDENTIFIER))) + { + have_slashes = true; + path.append("/"); + path.append(next->m_value); + } + if (match(GoLexer::OP_DOT)) + { + auto *name = Identifier(); + if (name) + { + if (have_slashes) + { + p->SetName(GoLexer::Token(GoLexer::TOK_IDENTIFIER, CopyString(path))); + } + return new GoASTSelectorExpr(p, name); + } + } + return r.error(); +} + +llvm::StringRef +GoParser::CopyString(llvm::StringRef s) +{ + return m_strings.insert(std::make_pair(s, 'x')).first->getKey(); +} + +void +GoParser::GetError(Error &error) +{ + llvm::StringRef want; + if (m_failed) + want = m_last_tok == GoLexer::TOK_INVALID ? DescribeToken(m_last_tok) : m_last; + else + want = m_error; + size_t len = m_lexer.BytesRemaining(); + if (len > 10) + len = 10; + llvm::StringRef got; + if (len == 0) + got = ""; + else + got = m_lexer.GetString(len); + error.SetErrorStringWithFormat("Syntax error: expected %s before '%s'.", want.str().c_str(), got.str().c_str()); +} Index: source/Plugins/ExpressionParser/Go/GoUserExpression.h =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoUserExpression.h @@ -0,0 +1,99 @@ +//===-- GoUserExpression.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_GoUserExpression_h_ +#define liblldb_GoUserExpression_h_ + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Target/ExecutionContext.h" + +namespace lldb_private +{ +class GoParser; + +class GoPersistentExpressionState : public PersistentExpressionState +{ + public: + GoPersistentExpressionState(); + + ConstString GetNextPersistentVariableName() override; + + void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; + + lldb::addr_t + LookupSymbol(const ConstString &name) override + { + return LLDB_INVALID_ADDRESS; + } + + static bool + classof(const PersistentExpressionState *pv) + { + return pv->getKind() == PersistentExpressionState::eKindGo; + } + + private: + uint32_t m_next_persistent_variable_id; ///< The counter used by GetNextResultName(). +}; + +//---------------------------------------------------------------------- +/// @class GoUserExpression GoUserExpression.h "lldb/Expression/GoUserExpression.h" +/// @brief Encapsulates a single expression for use with Go +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. GoUserExpression encapsulates +/// the objects needed to parse and interpret an expression. +//---------------------------------------------------------------------- +class GoUserExpression : public UserExpression +{ + public: + GoUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type); + + virtual bool Parse(Stream &error_stream, ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) override; + + virtual lldb::ExpressionResults Execute(Stream &error_stream, ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) override; + + bool + CanInterpret() override + { + return true; + } + bool + FinalizeJITExecution(Stream &error_stream, ExecutionContext &exe_ctx, lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) override + { + return true; + } + + private: + class GoInterpreter; + std::unique_ptr m_interpreter; +}; + +} // namespace lldb_private + +#endif // liblldb_GoUserExpression_h_ Index: source/Plugins/ExpressionParser/Go/GoUserExpression.cpp =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoUserExpression.cpp @@ -0,0 +1,735 @@ +//===-- GoUserExpression.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#if HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include +#include + +#include "GoUserExpression.h" + +#include "lldb/lldb-private.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataEncoder.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Symbol/GoASTContext.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallUserExpression.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" + +#include "Plugins/ExpressionParser/Go/GoAST.h" +#include "Plugins/ExpressionParser/Go/GoParser.h" + +using namespace lldb_private; +using namespace lldb; + +class GoUserExpression::GoInterpreter +{ + public: + GoInterpreter(ExecutionContext &exe_ctx, const char *expr) + : m_exe_ctx(exe_ctx), m_frame(exe_ctx.GetFrameSP()), m_parser(expr) + { + if (m_frame) + { + const SymbolContext &ctx = m_frame->GetSymbolContext(eSymbolContextFunction); + ConstString fname = ctx.GetFunctionName(); + if (fname.GetLength() > 0) + { + size_t dot = fname.GetStringRef().find('.'); + if (dot != llvm::StringRef::npos) + m_package = llvm::StringRef(fname.AsCString(), dot); + } + } + } + + void + set_use_dynamic(DynamicValueType use_dynamic) + { + m_use_dynamic = use_dynamic; + } + + bool Parse(); + lldb::ValueObjectSP Evaluate(ExecutionContext &exe_ctx); + lldb::ValueObjectSP EvaluateStatement(const GoASTStmt *s); + lldb::ValueObjectSP EvaluateExpr(const GoASTExpr *e); + + ValueObjectSP + VisitBadExpr(const GoASTBadExpr *e) + { + m_parser.GetError(m_error); + return nullptr; + } + ValueObjectSP VisitParenExpr(const GoASTParenExpr *e); + ValueObjectSP VisitIdent(const GoASTIdent *e); + ValueObjectSP VisitStarExpr(const GoASTStarExpr *e); + ValueObjectSP VisitSelectorExpr(const GoASTSelectorExpr *e); + ValueObjectSP VisitBasicLit(const GoASTBasicLit *e); + ValueObjectSP VisitIndexExpr(const GoASTIndexExpr *e); + ValueObjectSP VisitUnaryExpr(const GoASTUnaryExpr *e); + ValueObjectSP VisitCallExpr(const GoASTCallExpr *e); + ValueObjectSP + VisitTypeAssertExpr(const GoASTTypeAssertExpr *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitBinaryExpr(const GoASTBinaryExpr *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitArrayType(const GoASTArrayType *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitChanType(const GoASTChanType *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitCompositeLit(const GoASTCompositeLit *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitEllipsis(const GoASTEllipsis *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitFuncType(const GoASTFuncType *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitFuncLit(const GoASTFuncLit *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitInterfaceType(const GoASTInterfaceType *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitKeyValueExpr(const GoASTKeyValueExpr *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitMapType(const GoASTMapType *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitSliceExpr(const GoASTSliceExpr *e) + { + return NotImplemented(e); + } + ValueObjectSP + VisitStructType(const GoASTStructType *e) + { + return NotImplemented(e); + } + + CompilerType EvaluateType(const GoASTExpr *e); + + Error & + error() + { + return m_error; + } + + private: + std::nullptr_t + NotImplemented(const GoASTExpr *e) + { + m_error.SetErrorStringWithFormat("%s node not implemented", e->GetKindName()); + return nullptr; + } + + ExecutionContext m_exe_ctx; + lldb::StackFrameSP m_frame; + GoParser m_parser; + DynamicValueType m_use_dynamic; + Error m_error; + llvm::StringRef m_package; + std::vector> m_statements; +}; + +VariableSP +FindGlobalVariable(TargetSP target, llvm::Twine name) +{ + ConstString fullname(name.str()); + VariableList variable_list; + const bool append = true; + if (!target) + { + return nullptr; + } + const uint32_t match_count = target->GetImages().FindGlobalVariables(fullname, append, 1, variable_list); + if (match_count == 1) + { + return variable_list.GetVariableAtIndex(0); + } + return nullptr; +} + +CompilerType +LookupType(TargetSP target, ConstString name) +{ + if (!target) + return CompilerType(); + SymbolContext sc; + TypeList type_list; + uint32_t num_matches = target->GetImages().FindTypes(sc, name, false, 2, type_list); + if (num_matches > 0) + { + return type_list.GetTypeAtIndex(0)->GetFullCompilerType(); + } + return CompilerType(); +} +GoUserExpression::GoUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type) + : UserExpression(exe_scope, expr, expr_prefix, language, desired_type) +{ +} + +bool +GoUserExpression::Parse(Stream &error_stream, ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) +{ + InstallContext(exe_ctx); + m_interpreter.reset(new GoInterpreter(exe_ctx, GetUserText())); + if (m_interpreter->Parse()) + return true; + const char *error_cstr = m_interpreter->error().AsCString(); + if (error_cstr && error_cstr[0]) + error_stream.Printf("error: %s\n", error_cstr); + else + error_stream.Printf("error: expression can't be interpreted or run\n"); + return false; +} + +lldb::ExpressionResults +GoUserExpression::Execute(Stream &error_stream, ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, lldb::ExpressionVariableSP &result) +{ + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); + + lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); + lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; + + Process *process = exe_ctx.GetProcessPtr(); + Target *target = exe_ctx.GetTargetPtr(); + + if (target == nullptr || process == nullptr || process->GetState() != lldb::eStateStopped) + { + if (execution_policy == eExecutionPolicyAlways) + { + if (log) + log->Printf("== [GoUserExpression::Evaluate] Expression may not run, but is not constant =="); + + error_stream.Printf("expression needed to run but couldn't"); + + return execution_results; + } + } + + m_interpreter->set_use_dynamic(options.GetUseDynamic()); + ValueObjectSP result_val_sp = m_interpreter->Evaluate(exe_ctx); + Error err = m_interpreter->error(); + m_interpreter.reset(); + + if (!result_val_sp) + { + const char *error_cstr = err.AsCString(); + if (error_cstr && error_cstr[0]) + error_stream.Printf("error: %s\n", error_cstr); + else + error_stream.Printf("error: expression can't be interpreted or run\n"); + return lldb::eExpressionDiscarded; + } + result.reset(new ExpressionVariable(ExpressionVariable::eKindGo)); + result->m_live_sp = result->m_frozen_sp = result_val_sp; + result->m_flags |= ExpressionVariable::EVIsProgramReference; + PersistentExpressionState *pv = target->GetPersistentExpressionStateForLanguage(eLanguageTypeGo); + if (pv != nullptr) + { + result->SetName(pv->GetNextPersistentVariableName()); + pv->AddVariable(result); + } + return lldb::eExpressionCompleted; +} + +bool +GoUserExpression::GoInterpreter::Parse() +{ + for (std::unique_ptr stmt(m_parser.Statement()); stmt; stmt.reset(m_parser.Statement())) + { + if (m_parser.Failed()) + break; + m_statements.emplace_back(std::move(stmt)); + } + if (m_parser.Failed() || !m_parser.AtEOF()) + m_parser.GetError(m_error); + + return m_error.Success(); +} + +ValueObjectSP +GoUserExpression::GoInterpreter::Evaluate(ExecutionContext &exe_ctx) +{ + m_exe_ctx = exe_ctx; + ValueObjectSP result; + for (const std::unique_ptr &stmt : m_statements) + { + result = EvaluateStatement(stmt.get()); + if (m_error.Fail()) + return nullptr; + } + return result; +} + +ValueObjectSP +GoUserExpression::GoInterpreter::EvaluateStatement(const lldb_private::GoASTStmt *stmt) +{ + ValueObjectSP result; + switch (stmt->GetKind()) + { + case GoASTNode::eBlockStmt: + { + const GoASTBlockStmt *block = llvm::cast(stmt); + for (size_t i = 0; i < block->NumList(); ++i) + result = EvaluateStatement(block->GetList(i)); + break; + } + case GoASTNode::eBadStmt: + m_parser.GetError(m_error); + break; + case GoASTNode::eExprStmt: + { + const GoASTExprStmt *expr = llvm::cast(stmt); + return EvaluateExpr(expr->GetX()); + } + default: + m_error.SetErrorStringWithFormat("%s node not supported", stmt->GetKindName()); + } + return result; +} + +ValueObjectSP +GoUserExpression::GoInterpreter::EvaluateExpr(const lldb_private::GoASTExpr *e) +{ + if (e) + return e->Visit(this); + return ValueObjectSP(); +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitParenExpr(const lldb_private::GoASTParenExpr *e) +{ + return EvaluateExpr(e->GetX()); +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitIdent(const GoASTIdent *e) +{ + ValueObjectSP val; + if (m_frame) + { + VariableSP var_sp; + std::string varname = e->GetName().m_value.str(); + if (varname.size() > 1 && varname[0] == '$') + { + RegisterContextSP reg_ctx_sp = m_frame->GetRegisterContext(); + const RegisterInfo *reg = reg_ctx_sp->GetRegisterInfoByName(varname.c_str() + 1); + if (reg) + { + std::string type; + switch (reg->encoding) + { + case lldb::eEncodingSint: + type.append("int"); + break; + case lldb::eEncodingUint: + type.append("uint"); + break; + case lldb::eEncodingIEEE754: + type.append("float"); + break; + default: + m_error.SetErrorString("Invaild register encoding"); + return nullptr; + } + switch (reg->byte_size) + { + case 8: + type.append("64"); + break; + case 4: + type.append("32"); + break; + case 2: + type.append("16"); + break; + case 1: + type.append("8"); + break; + default: + m_error.SetErrorString("Invaild register size"); + return nullptr; + } + ValueObjectSP regVal = + ValueObjectRegister::Create(m_frame.get(), reg_ctx_sp, reg->kinds[eRegisterKindLLDB]); + CompilerType goType = LookupType(m_frame->CalculateTarget(), ConstString(type)); + if (regVal) + { + regVal = regVal->Cast(goType); + return regVal; + } + } + m_error.SetErrorString("Invaild register name"); + return nullptr; + } + VariableListSP var_list_sp(m_frame->GetInScopeVariableList(false)); + if (var_list_sp) + { + var_sp = var_list_sp->FindVariable(ConstString(varname)); + if (var_sp) + val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic); + else + { + // When a variable is on the heap instead of the stack, go records a variable + // '&x' instead of 'x'. + var_sp = var_list_sp->FindVariable(ConstString("&" + varname)); + if (var_sp) + { + val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic); + if (val) + val = val->Dereference(m_error); + if (m_error.Fail()) + return nullptr; + } + } + } + if (!val) + { + m_error.Clear(); + TargetSP target = m_frame->CalculateTarget(); + if (!target) + { + m_error.SetErrorString("No target"); + return nullptr; + } + var_sp = FindGlobalVariable(target, m_package + "." + e->GetName().m_value); + if (var_sp) + return m_frame->TrackGlobalVariable(var_sp, m_use_dynamic); + } + } + if (!val) + m_error.SetErrorStringWithFormat("Unknown variable %s", e->GetName().m_value.str().c_str()); + return val; +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitStarExpr(const GoASTStarExpr *e) +{ + ValueObjectSP target = EvaluateExpr(e->GetX()); + if (!target) + return nullptr; + return target->Dereference(m_error); +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitSelectorExpr(const lldb_private::GoASTSelectorExpr *e) +{ + ValueObjectSP target = EvaluateExpr(e->GetX()); + if (target) + { + if (target->GetCompilerType().IsPointerType()) + { + target = target->Dereference(m_error); + if (m_error.Fail()) + return nullptr; + } + ConstString field(e->GetSel()->GetName().m_value); + ValueObjectSP result = target->GetChildMemberWithName(field, true); + if (!result) + m_error.SetErrorStringWithFormat("Unknown child %s", field.AsCString()); + return result; + } + if (const GoASTIdent *package = llvm::dyn_cast(e->GetX())) + { + if (VariableSP global = FindGlobalVariable(m_exe_ctx.GetTargetSP(), + package->GetName().m_value + "." + e->GetSel()->GetName().m_value)) + { + if (m_frame) + { + m_error.Clear(); + return m_frame->GetValueObjectForFrameVariable(global, m_use_dynamic); + } + } + } + if (const GoASTBasicLit *packageLit = llvm::dyn_cast(e->GetX())) + { + if (packageLit->GetValue().m_type == GoLexer::LIT_STRING) + { + std::string value = packageLit->GetValue().m_value.str(); + value = value.substr(1, value.size() - 2); + if (VariableSP global = + FindGlobalVariable(m_exe_ctx.GetTargetSP(), value + "." + e->GetSel()->GetName().m_value)) + { + if (m_frame) + { + m_error.Clear(); + return m_frame->TrackGlobalVariable(global, m_use_dynamic); + } + } + } + } + // EvaluateExpr should have already set m_error. + return target; +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitBasicLit(const lldb_private::GoASTBasicLit *e) +{ + std::string value = e->GetValue().m_value.str(); + if (e->GetValue().m_type != GoLexer::LIT_INTEGER) + { + m_error.SetErrorStringWithFormat("Unsupported literal %s", value.c_str()); + return nullptr; + } + errno = 0; + int64_t intvalue = strtol(value.c_str(), NULL, 0); + if (errno != 0) + { + m_error.SetErrorToErrno(); + return nullptr; + } + DataBufferSP buf(new DataBufferHeap(sizeof(intvalue), 0)); + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + { + m_error.SetErrorString("No target"); + return nullptr; + } + ByteOrder order = target->GetArchitecture().GetByteOrder(); + uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + DataEncoder enc(buf, order, addr_size); + enc.PutU64(0, static_cast(intvalue)); + DataExtractor data(buf, order, addr_size); + + CompilerType type = LookupType(target, ConstString("int64")); + return ValueObject::CreateValueObjectFromData(nullptr, data, m_exe_ctx, type); +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitIndexExpr(const lldb_private::GoASTIndexExpr *e) +{ + ValueObjectSP target = EvaluateExpr(e->GetX()); + if (!target) + return nullptr; + ValueObjectSP index = EvaluateExpr(e->GetIndex()); + if (!index) + return nullptr; + bool is_signed; + if (!index->GetCompilerType().IsIntegerType(is_signed)) + { + m_error.SetErrorString("Unsupported index"); + return nullptr; + } + size_t idx; + if (is_signed) + idx = index->GetValueAsSigned(0); + else + idx = index->GetValueAsUnsigned(0); + if (GoASTContext::IsGoSlice(target->GetCompilerType())) + { + target = target->GetStaticValue(); + ValueObjectSP cap = target->GetChildMemberWithName(ConstString("cap"), true); + if (cap) + { + uint64_t capval = cap->GetValueAsUnsigned(0); + if (idx >= capval) + { + m_error.SetErrorStringWithFormat("Invalid index %" PRIu64 " , cap = %" PRIu64, uint64_t(idx), capval); + return nullptr; + } + } + target = target->GetChildMemberWithName(ConstString("array"), true); + if (target && m_use_dynamic != eNoDynamicValues) + { + ValueObjectSP dynamic = target->GetDynamicValue(m_use_dynamic); + if (dynamic) + target = dynamic; + } + if (!target) + return nullptr; + return target->GetSyntheticArrayMember(idx, true); + } + return target->GetChildAtIndex(idx, true); +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitUnaryExpr(const GoASTUnaryExpr *e) +{ + ValueObjectSP x = EvaluateExpr(e->GetX()); + if (!x) + return nullptr; + switch (e->GetOp()) + { + case GoLexer::OP_AMP: + { + CompilerType type = x->GetCompilerType().GetPointerType(); + uint64_t address = x->GetAddressOf(); + return ValueObject::CreateValueObjectFromAddress(nullptr, address, m_exe_ctx, type); + } + case GoLexer::OP_PLUS: + return x; + default: + m_error.SetErrorStringWithFormat("Operator %s not supported", + GoLexer::LookupToken(e->GetOp()).str().c_str()); + return nullptr; + } +} + +CompilerType +GoUserExpression::GoInterpreter::EvaluateType(const GoASTExpr *e) +{ + TargetSP target = m_exe_ctx.GetTargetSP(); + if (auto *id = llvm::dyn_cast(e)) + { + CompilerType result = LookupType(target, ConstString(id->GetName().m_value)); + if (result.IsValid()) + return result; + std::string fullname = (m_package + "." + id->GetName().m_value).str(); + result = LookupType(target, ConstString(fullname)); + if (!result) + m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str()); + return result; + } + if (auto *sel = llvm::dyn_cast(e)) + { + std::string package; + if (auto *pkg_node = llvm::dyn_cast(sel->GetX())) + { + package = pkg_node->GetName().m_value.str(); + } + else if (auto *str_node = llvm::dyn_cast(sel->GetX())) + { + if (str_node->GetValue().m_type == GoLexer::LIT_STRING) + { + package = str_node->GetValue().m_value.substr(1).str(); + package.resize(package.length() - 1); + } + } + if (package.empty()) + { + m_error.SetErrorStringWithFormat("Invalid %s in type expression", sel->GetX()->GetKindName()); + return CompilerType(); + } + std::string fullname = (package + "." + sel->GetSel()->GetName().m_value).str(); + CompilerType result = LookupType(target, ConstString(fullname)); + if (!result) + m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str()); + return result; + } + if (auto *star = llvm::dyn_cast(e)) + { + CompilerType elem = EvaluateType(star->GetX()); + return elem.GetPointerType(); + } + if (auto *paren = llvm::dyn_cast(e)) + return EvaluateType(paren->GetX()); + if (auto *array = llvm::dyn_cast(e)) + { + CompilerType elem = EvaluateType(array->GetElt()); + } + + m_error.SetErrorStringWithFormat("Invalid %s in type expression", e->GetKindName()); + return CompilerType(); +} + +ValueObjectSP +GoUserExpression::GoInterpreter::VisitCallExpr(const lldb_private::GoASTCallExpr *e) +{ + ValueObjectSP x = EvaluateExpr(e->GetFun()); + if (x || e->NumArgs() != 1) + { + m_error.SetErrorStringWithFormat("Code execution not supported"); + return nullptr; + } + m_error.Clear(); + CompilerType type = EvaluateType(e->GetFun()); + if (!type) + { + return nullptr; + } + ValueObjectSP value = EvaluateExpr(e->GetArgs(0)); + if (!value) + return nullptr; + // TODO: Handle special conversions + return value->Cast(type); +} + +GoPersistentExpressionState::GoPersistentExpressionState() : PersistentExpressionState(eKindGo) +{ +} + +ConstString +GoPersistentExpressionState::GetNextPersistentVariableName() +{ + char name_cstr[256]; + // We can't use the same variable format as clang. + ::snprintf(name_cstr, sizeof(name_cstr), "$go%u", m_next_persistent_variable_id++); + ConstString name(name_cstr); + return name; +} + +void +GoPersistentExpressionState::RemovePersistentVariable(lldb::ExpressionVariableSP variable) +{ + RemoveVariable(variable); + + const char *name = variable->GetName().AsCString(); + + if (*(name++) != '$') + return; + if (*(name++) != 'g') + return; + if (*(name++) != 'o') + return; + + if (strtoul(name, NULL, 0) == m_next_persistent_variable_id - 1) + m_next_persistent_variable_id--; +} Index: source/Plugins/ExpressionParser/Go/Makefile =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/ExpressionParser/Clang ---------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginExpressionParserGo +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile Index: source/Plugins/ExpressionParser/Go/gen_go_ast.py =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/gen_go_ast.py @@ -0,0 +1,356 @@ +import StringIO + +def addNodes(): + addNode("ArrayType", "Expr", "len", "Expr", "elt", "Expr") + addNode("AssignStmt", "Stmt", "lhs", "[]Expr", "rhs", "[]Expr", "define", "bool") + addNode("BadDecl", "Decl") + addNode("BadExpr", "Expr") + addNode("BadStmt", "Stmt") + addNode("BasicLit", "Expr", "value", "Token") + addNode("BinaryExpr", "Expr", "x", "Expr", "y", "Expr", "op", "TokenType") + addNode("BlockStmt", "Stmt", "list", "[]Stmt") + addNode("Ident", "Expr", "name", "Token") + addNode("BranchStmt", "Stmt", "label", "Ident", "tok", "TokenType") + addNode("CallExpr", "Expr", "fun", "Expr", "args", "[]Expr", "ellipsis", "bool") + addNode("CaseClause", "Stmt", "list", "[]Expr", "body", "[]Stmt") + addNode("ChanType", "Expr", "dir", "ChanDir", "value", "Expr") + addNode("CommClause", "Stmt", "comm", "Stmt", "body", "[]Stmt") + addNode("CompositeLit", "Expr", "type", "Expr", "elts", "[]Expr") + addNode("DeclStmt", "Stmt", "decl", "Decl") + addNode("DeferStmt", "Stmt", "call", "CallExpr") + addNode("Ellipsis", "Expr", "elt", "Expr") + addNode("EmptyStmt", "Stmt") + addNode("ExprStmt", "Stmt", "x", "Expr") + addNode("Field", "Node", "names", "[]Ident", "type", "Expr", "tag", "BasicLit") + addNode("FieldList", "Node", "list", "[]Field") + addNode("ForStmt", "Stmt", "init", "Stmt", "cond", "Expr", "post", "Stmt", "body", "BlockStmt") + addNode("FuncType", "Expr", "params", "FieldList", "results", "FieldList") + addNode("FuncDecl", "Decl", "recv", "FieldList", "name", "Ident", "type", "FuncType", "body", "BlockStmt") + addNode("FuncLit", "Expr", "type", "FuncType", "body", "BlockStmt") + addNode("GenDecl", "Decl", "tok", "TokenType", "specs", "[]Spec") + addNode("GoStmt", "Stmt", "call", "CallExpr") + addNode("IfStmt", "Stmt", "init", "Stmt", "cond", "Expr", "body", "BlockStmt", "els", "Stmt") + addNode("ImportSpec", "Spec", "name", "Ident", "path", "BasicLit") + addNode("IncDecStmt", "Stmt", "x", "Expr", "tok", "TokenType") + addNode("IndexExpr", "Expr", "x", "Expr", "index", "Expr") + addNode("InterfaceType", "Expr", "methods", "FieldList") + addNode("KeyValueExpr", "Expr", "key", "Expr", "value", "Expr") + addNode("LabeledStmt", "Stmt", "label", "Ident", "stmt", "Stmt") + addNode("MapType", "Expr", "key", "Expr", "value", "Expr") + addNode("ParenExpr", "Expr", "x", "Expr") + addNode("RangeStmt", "Stmt", "key", "Expr", "value", "Expr", "define", "bool", "x", "Expr", "body", "BlockStmt") + addNode("ReturnStmt", "Stmt", "results", "[]Expr") + addNode("SelectStmt", "Stmt", "body", "BlockStmt") + addNode("SelectorExpr", "Expr", "x", "Expr", "sel", "Ident") + addNode("SendStmt", "Stmt", "chan", "Expr", "value", "Expr") + addNode("SliceExpr", "Expr", "x", "Expr", "low", "Expr", "high", "Expr", "max", "Expr", "slice3", "bool") + addNode("StarExpr", "Expr", "x", "Expr") + addNode("StructType", "Expr", "fields", "FieldList") + addNode("SwitchStmt", "Stmt", "init", "Stmt", "tag", "Expr", "body", "BlockStmt") + addNode("TypeAssertExpr", "Expr", "x", "Expr", "type", "Expr") + addNode("TypeSpec", "Spec", "name", "Ident", "type", "Expr") + addNode("TypeSwitchStmt", "Stmt", "init", "Stmt", "assign", "Stmt", "body", "BlockStmt") + addNode("UnaryExpr", "Expr", "op", "TokenType", "x", "Expr") + addNode("ValueSpec", "Spec", "names", "[]Ident", "type", "Expr", "values", "[]Expr") + addParent("Decl", "Node") + addParent("Expr", "Node") + addParent("Spec", "Node") + addParent("Stmt", "Node") + + +class Member(object): + def __init__(self, name, typename): + self.title = name.title() + self.sname = name + self.mname = 'm_' + name + self.is_list = typename.startswith("[]") + self.is_value = isValueType(typename) + if self.is_value: + self.argtype = typename + self.mtype = typename + elif self.is_list: + self.argtype = 'GoAST' + typename[2:] + self.mtype = 'std::vector >' % self.argtype + else: + self.argtype = 'GoAST' + typename + self.mtype = 'std::unique_ptr<%s>' % self.argtype + self.mname = self.mname + '_up' + + +kinds = {} +parentClasses = StringIO.StringIO() +childClasses = StringIO.StringIO() +walker = StringIO.StringIO() + +def startClass(name, parent, out): + out.write(""" +class GoAST%s : public GoAST%s +{ + public: +""" % (name, parent)) + +def endClass(name, out): + out.write(""" + %(name)s(const %(name)s &) = delete; + const %(name)s &operator=(const %(name)s &) = delete; +}; +""" % {'name': 'GoAST' + name}) + +def addNode(name, parent, *children): + startClass(name, parent, childClasses) + l = kinds.setdefault(parent, []) + l.append(name) + children = createMembers(name, children) + addConstructor(name, parent, children) + childClasses.write(""" + const char * + GetKindName() const override + { + return "%(name)s"; + } + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() == e%(name)s; + } + """ % {'name':name}) + addChildren(name, children) + endClass(name, childClasses) + +def isValueType(typename): + if typename[0].islower(): + return True + if typename[0].isupper(): + return typename.startswith('Token') or typename == 'ChanDir' + return False + + +def createMembers(name, children): + l = len(children) + if (l % 2) != 0: + raise Exception("Invalid children for %s: %s" % (name, children)) + return [Member(children[i], children[i + 1]) for i in xrange(0, l, 2)] + + +def addConstructor(name, parent, children): + for c in children: + if c.is_list: + children = [x for x in children if x.is_value] + break + childClasses.write(' ') + if len(children) == 1: + childClasses.write('explicit ') + childClasses.write('GoAST%s(' % name) + for i in xrange(len(children)): + if i > 0: + childClasses.write(', ') + + c = children[i] + if c.is_value: + childClasses.write(c.argtype) + childClasses.write(' ') + else: + childClasses.write('%s *' % c.argtype) + childClasses.write(c.sname) + childClasses.write(') : GoAST%s(e%s)' % (parent, name)) + for c in children: + childClasses.write(', ') + childClasses.write('%(mname)s(%(sname)s)' % c.__dict__) + childClasses.write(""" {} + ~GoAST%s() override = default; +""" % name) + + +def addChildren(name, children): + if len(children) == 0: + return + walker.write(""" + case e%(n)s: + { + GoAST%(n)s *n = llvm::cast(this); + (void)n;""" % {'n':name}) + for c in children: + if c.is_list: + childClasses.write(""" + size_t + Num%(title)s() const + { + return %(mname)s.size(); + } + const %(argtype)s * + Get%(title)s(int i) const + { + return %(mname)s[i].get(); + } + void + Add%(title)s(%(argtype)s *%(sname)s) + { + %(mname)s.push_back(std::unique_ptr<%(argtype)s>(%(sname)s)); + } +""" % c.__dict__) + walker.write(""" + for (auto& e : n->%s) { v(e.get()); }""" % c.mname) + else: + const = '' + get = '' + set = '' + t = c.argtype + if isValueType(t): + set = '%(mname)s = %(sname)s' % c.__dict__ + t = t + ' ' + else: + t = t + ' *' + const = 'const ' + get = '.get()' + set = '%(mname)s.reset(%(sname)s)' % c.__dict__ + walker.write(""" + v(n->%s.get());""" % c.mname) + childClasses.write(""" + %(const)s%(type)s + Get%(title)s() const + { + return %(mname)s%(get)s; + } + void + Set%(title)s(%(type)s%(sname)s) + { + %(set)s; + } +""" % {'const':const, 'title': c.title, 'sname': c.sname, 'get': get, 'set': set, 'type': t, 'mname': c.mname}) + childClasses.write('\n private:\n friend class GoASTNode;\n') + walker.write(""" + return; + }""") + for c in children: + childClasses.write(' %s %s;\n' %(c.mtype, c.mname)) + + +def addParent(name, parent): + startClass(name, parent, parentClasses) + l = kinds[name] + minName = l[0] + maxName = l[-1] + parentClasses.write(""" template R Visit(V *v) const; + + static bool + classof(const GoASTNode *n) + { + return n->GetKind() >= e%s && n->GetKind() <= e%s; + } + + protected: + explicit GoAST%s(NodeKind kind) : GoASTNode(kind) { } + private: +""" % (minName, maxName, name)) + endClass(name, parentClasses) + +addNodes() + +print """//===-- GoAST.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// DO NOT EDIT. +// Generated by gen_go_ast.py + +#ifndef liblldb_GoAST_h +#define liblldb_GoAST_h + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "llvm/Support/Casting.h" +#include "Plugins/ExpressionParser/Go/GoLexer.h" + +namespace lldb_private +{ + +class GoASTNode +{ + public: + typedef GoLexer::TokenType TokenType; + typedef GoLexer::Token Token; + enum ChanDir + { + eChanBidir, + eChanSend, + eChanRecv, + }; + enum NodeKind + {""" +for l in kinds.itervalues(): + for x in l: + print " e%s," % x +print """ }; + + virtual ~GoASTNode() = default; + + NodeKind + GetKind() const + { + return m_kind; + } + + virtual const char *GetKindName() const = 0; + + template void WalkChildren(V &v); + + protected: + explicit GoASTNode(NodeKind kind) : m_kind(kind) { } + + private: + const NodeKind m_kind; + + GoASTNode(const GoASTNode &) = delete; + const GoASTNode &operator=(const GoASTNode &) = delete; +}; +""" + + +print parentClasses.getvalue() +print childClasses.getvalue() + +for k, l in kinds.iteritems(): + if k == 'Node': + continue + print """ +template +R GoAST%s::Visit(V* v) const +{ + switch(GetKind()) + {""" % k + for subtype in l: + print """ case e%(n)s: + return v->Visit%(n)s(llvm::cast(this));""" % {'n':subtype} + + print """ default: + assert(false && "Invalid kind"); + } +}""" + +print """ +template +void GoASTNode::WalkChildren(V &v) +{ + switch (m_kind) + { +""" +print walker.getvalue() +print""" + case eEmptyStmt: + case eBadDecl: + case eBadExpr: + case eBadStmt: + break; + } +} + +} // namespace lldb_private + +#endif +""" Index: source/Symbol/GoASTContext.cpp =================================================================== --- source/Symbol/GoASTContext.cpp +++ source/Symbol/GoASTContext.cpp @@ -24,6 +24,7 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" +#include "Plugins/ExpressionParser/Go/GoUserExpression.h" #include "Plugins/SymbolFile/DWARF/DWARFASTParserGo.h" using namespace lldb; @@ -200,9 +201,7 @@ }; GoStruct(int kind, const ConstString &name, int64_t byte_size) - : GoType(kind, name) - , m_is_complete(false) - , m_byte_size(byte_size) + : GoType(kind == 0 ? KIND_STRUCT : kind, name), m_is_complete(false), m_byte_size(byte_size) { } @@ -327,14 +326,20 @@ if (language == eLanguageTypeGo) { ArchSpec arch; + std::shared_ptr go_ast_sp; if (module) + { arch = module->GetArchitecture(); + go_ast_sp = std::shared_ptr(new GoASTContext); + } else if (target) + { arch = target->GetArchitecture(); + go_ast_sp = std::shared_ptr(new GoASTContextForExpr(target->shared_from_this())); + } if (arch.IsValid()) { - std::shared_ptr go_ast_sp(new GoASTContext); go_ast_sp->SetAddressByteSize(arch.GetAddressByteSize()); return go_ast_sp; } @@ -414,6 +419,10 @@ return false; if (kind == GoType::KIND_PTR) return false; + if (kind == GoType::KIND_CHAN) + return false; + if (kind == GoType::KIND_MAP) + return false; if (kind == GoType::KIND_STRING) return false; if (kind == GoType::KIND_UNSAFEPOINTER) @@ -583,7 +592,8 @@ case GoType::KIND_PTR: case GoType::KIND_UNSAFEPOINTER: case GoType::KIND_CHAN: - // TODO: is map a pointer? string? function? + case GoType::KIND_MAP: + // TODO: is function a pointer? return true; default: return false; @@ -1064,6 +1074,11 @@ { return array->GetLength(); } + else if (t->IsTypedef()) + { + return t->GetElementType().GetNumChildren(omit_empty_base_classes); + } + return GetNumFields(type); } @@ -1491,3 +1506,13 @@ m_dwarf_ast_parser_ap.reset(new DWARFASTParserGo(*this)); return m_dwarf_ast_parser_ap.get(); } + +UserExpression * +GoASTContextForExpr::GetUserExpression(const char *expr, const char *expr_prefix, lldb::LanguageType language, + Expression::ResultType desired_type) +{ + TargetSP target = m_target_wp.lock(); + if (target) + return new GoUserExpression(*target, expr, expr_prefix, language, desired_type); + return nullptr; +} Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -44,6 +44,8 @@ #include "lldb/Interpreter/OptionValues.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/GoASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" @@ -1997,13 +1999,8 @@ TypeSystem *type_system = GetScratchTypeSystemForLanguage(nullptr, language, true); if (type_system) - { return type_system->GetPersistentExpressionState(); - } - else - { - return nullptr; - } + return nullptr; } UserExpression * Index: test/lang/go/expressions/TestExpressions.py =================================================================== --- /dev/null +++ test/lang/go/expressions/TestExpressions.py @@ -0,0 +1,113 @@ +"""Test the go expression parser/interpreter.""" + +import os, time +import unittest2 +import lldb +import lldbutil +from lldbtest import * + +class TestGoUserExpression(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @python_api_test + @skipIfRemote # Not remote test suit ready + @skipUnlessGoInstalled + def test_with_dsym_and_python_api(self): + """Test GoASTUserExpress.""" + self.buildGo() + self.launchProcess() + self.go_expressions() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line numbers to break inside main(). + self.main_source = "main.go" + self.break_line = line_number(self.main_source, '// Set breakpoint here.') + + def check_builtin(self, name, size=0, typeclass=lldb.eTypeClassBuiltin): + tl = self.target().FindTypes(name) + self.assertEqual(1, len(tl)) + t = list(tl)[0] + self.assertEqual(name, t.name) + self.assertEqual(typeclass, t.type) + if size > 0: + self.assertEqual(size, t.size) + + def launchProcess(self): + exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + bpt = target.BreakpointCreateByLocation(self.main_source, self.break_line) + self.assertTrue(bpt, VALID_BREAKPOINT) + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple (None, None, self.get_process_working_directory()) + + self.assertTrue(process, PROCESS_IS_VALID) + + # The stop reason of the thread should be breakpoint. + thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, bpt) + + # Make sure we stopped at the first breakpoint. + self.assertTrue (len(thread_list) != 0, "No thread stopped at our breakpoint.") + self.assertTrue (len(thread_list) == 1, "More than one thread stopped at our breakpoint.") + + frame = thread_list[0].GetFrameAtIndex(0) + self.assertTrue (frame, "Got a valid frame 0 frame.") + + def go_expressions(self): + frame = self.frame() + v = frame.EvaluateExpression("1") + self.assertEqual(1, v.GetValueAsSigned()) + x = frame.EvaluateExpression("x") + self.assertEqual(22, x.GetValueAsSigned()) + + a = frame.EvaluateExpression("a") + self.assertEqual(3, a.GetNumChildren()) + a0 = a.GetChildAtIndex(0) + self.assertEqual(8, a0.GetValueAsSigned()) + + # Array indexing + a0 = frame.EvaluateExpression("a[0]") + self.assertEqual(8, a0.GetValueAsSigned()) + + # Slice indexing + b1 = frame.EvaluateExpression("b[1]") + self.assertEqual(9, b1.GetValueAsSigned()) + + # Test global in this package + g = frame.EvaluateExpression("myGlobal") + self.assertEqual(17, g.GetValueAsSigned(), str(g)) + + # Global with package name + g = frame.EvaluateExpression("main.myGlobal") + self.assertEqual(17, g.GetValueAsSigned(), str(g)) + + # Global with quoted package name + g = frame.EvaluateExpression('"main".myGlobal') + self.assertEqual(17, g.GetValueAsSigned(), str(g)) + + # Casting with package local type + s = frame.EvaluateExpression("*(*myStruct)(i.data)") + sb = s.GetChildMemberWithName("a") + self.assertEqual(2, sb.GetValueAsSigned()) + + # casting with explicit package + s = frame.EvaluateExpression("*(*main.myStruct)(i.data)") + sb = s.GetChildMemberWithName("a") + self.assertEqual(2, sb.GetValueAsSigned()) + + # Casting quoted package + s = frame.EvaluateExpression('*(*"main".myStruct)(i.data)') + sb = s.GetChildMemberWithName("b") + self.assertEqual(-1, sb.GetValueAsSigned()) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/lang/go/expressions/main.go =================================================================== --- /dev/null +++ test/lang/go/expressions/main.go @@ -0,0 +1,21 @@ +package main + +import "fmt" + +type myStruct struct { + a, b int +} + +var myGlobal = 17 + +func myFunc(i interface{}) { + a := [...]int{8, 9, 10} + b := a[:] + x := 22 + fmt.Println(a, b, x, i, myGlobal) // Set breakpoint here. +} + +func main() { + s := myStruct {2, -1} + myFunc(s) +} \ No newline at end of file Index: unittests/CMakeLists.txt =================================================================== --- unittests/CMakeLists.txt +++ unittests/CMakeLists.txt @@ -23,6 +23,7 @@ llvm_config(${test_name} ${LLVM_LINK_COMPONENTS}) endfunction() +add_subdirectory(Expression) add_subdirectory(Host) add_subdirectory(Interpreter) add_subdirectory(ScriptInterpreter) Index: unittests/Expression/CMakeLists.txt =================================================================== --- /dev/null +++ unittests/Expression/CMakeLists.txt @@ -0,0 +1,3 @@ +add_lldb_unittest(ExpressionTests + GoParserTest.cpp + ) Index: unittests/Expression/GoParserTest.cpp =================================================================== --- /dev/null +++ unittests/Expression/GoParserTest.cpp @@ -0,0 +1,250 @@ +//===-- GoParserTest.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0) +// Workaround for MSVC standard library bug, which fails to include when +// exceptions are disabled. +#include +#endif + +#include + +#include "gtest/gtest.h" + +#include "lldb/Core/Error.h" +#include "lldb/Expression/GoParser.h" + +using namespace lldb_private; + +namespace +{ +struct ASTPrinter +{ + ASTPrinter(GoASTNode *n) { (*this)(n); } + + void + operator()(GoASTNode *n) + { + if (n == nullptr) + { + m_stream << "nil "; + return; + } + m_stream << "(" << n->GetKindName() << " "; + n->WalkChildren(*this); + if (auto *nn = llvm::dyn_cast(n)) + m_stream << nn->GetDefine() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << nn->GetValue().m_value.str() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << GoLexer::LookupToken(nn->GetOp()).str() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << nn->GetName().m_value.str() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << (nn->GetEllipsis() ? "..." : "") << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << nn->GetDir() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << GoLexer::LookupToken(nn->GetTok()).str() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << nn->GetDefine() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << nn->GetSlice3() << " "; + if (auto *nn = llvm::dyn_cast(n)) + m_stream << GoLexer::LookupToken(nn->GetOp()).str() << " "; + m_stream << ") "; + } + + const std::string + str() const + { + return m_stream.str(); + } + std::stringstream m_stream; +}; + +testing::AssertionResult +CheckStatement(const char *_s, const char *c_expr, const char *sexpr, const char *code) +{ + GoParser parser(code); + std::unique_ptr stmt(parser.Statement()); + if (parser.Failed() || !stmt) + { + Error err; + parser.GetError(err); + return testing::AssertionFailure() << "Error parsing " << c_expr << "\n\t" << err.AsCString(); + } + std::string actual_sexpr = ASTPrinter(stmt.get()).str(); + if (actual_sexpr == sexpr) + return testing::AssertionSuccess(); + return testing::AssertionFailure() << "Parsing: " << c_expr << "\nExpected: " << sexpr + << "\nGot: " << actual_sexpr; +} +} // namespace + +#define EXPECT_PARSE(s, c) EXPECT_PRED_FORMAT2(CheckStatement, s, c) + +TEST(GoParserTest, ParseBasicLiterals) +{ + EXPECT_PARSE("(ExprStmt (BasicLit 0 ) ) ", "0"); + EXPECT_PARSE("(ExprStmt (BasicLit 42 ) ) ", "42"); + EXPECT_PARSE("(ExprStmt (BasicLit 0600 ) ) ", "0600"); + EXPECT_PARSE("(ExprStmt (BasicLit 0xBadFace ) ) ", "0xBadFace"); + EXPECT_PARSE("(ExprStmt (BasicLit 170141183460469231731687303715884105727 ) ) ", + "170141183460469231731687303715884105727"); + + EXPECT_PARSE("(ExprStmt (BasicLit 0. ) ) ", "0."); + EXPECT_PARSE("(ExprStmt (BasicLit 72.40 ) ) ", "72.40"); + EXPECT_PARSE("(ExprStmt (BasicLit 072.40 ) ) ", "072.40"); + EXPECT_PARSE("(ExprStmt (BasicLit 2.71828 ) ) ", "2.71828"); + EXPECT_PARSE("(ExprStmt (BasicLit 1.e+0 ) ) ", "1.e+0"); + EXPECT_PARSE("(ExprStmt (BasicLit 6.67428e-11 ) ) ", "6.67428e-11"); + EXPECT_PARSE("(ExprStmt (BasicLit 1E6 ) ) ", "1E6"); + EXPECT_PARSE("(ExprStmt (BasicLit .12345E+6 ) ) ", ".12345E+6"); + + EXPECT_PARSE("(ExprStmt (BasicLit 0i ) ) ", "0i"); + EXPECT_PARSE("(ExprStmt (BasicLit 011i ) ) ", "011i"); + EXPECT_PARSE("(ExprStmt (BasicLit 0.i ) ) ", "0.i"); + EXPECT_PARSE("(ExprStmt (BasicLit 2.71828i ) ) ", "2.71828i"); + EXPECT_PARSE("(ExprStmt (BasicLit 6.67428e-11i ) ) ", "6.67428e-11i"); + EXPECT_PARSE("(ExprStmt (BasicLit 1E6i ) ) ", "1E6i"); + EXPECT_PARSE("(ExprStmt (BasicLit .12345E+6i ) ) ", ".12345E+6i"); + + EXPECT_PARSE("(ExprStmt (BasicLit 'a' ) ) ", "'a'"); + EXPECT_PARSE("(ExprStmt (BasicLit '本' ) ) ", "'本'"); + EXPECT_PARSE("(ExprStmt (BasicLit \"abc\" ) ) ", "\"abc\""); + EXPECT_PARSE("(ExprStmt (BasicLit `abc` ) ) ", "`abc`"); + EXPECT_PARSE("(ExprStmt (BasicLit `ab\nc` ) ) ", "`ab\nc`"); +} + +TEST(GoParserTest, ParseOperand) +{ + EXPECT_PARSE("(ExprStmt (Ident a ) ) ", "a"); + EXPECT_PARSE("(ExprStmt (Ident _x9 ) ) ", "_x9"); + EXPECT_PARSE("(ExprStmt (Ident ThisVariableIsExported ) ) ", "ThisVariableIsExported"); + EXPECT_PARSE("(ExprStmt (Ident αβ ) ) ", "αβ"); + + EXPECT_PARSE("(ExprStmt (SelectorExpr (Ident math ) (Ident Sin ) ) ) ", "math.Sin"); +} + +TEST(GoParserTest, ParseCompositeLiterals) +{ + EXPECT_PARSE("(ExprStmt (CompositeLit (Ident Point3D ) ) ) ", "Point3D{}"); + EXPECT_PARSE("(ExprStmt (CompositeLit (Ident Line ) (Ident origin ) (CompositeLit (Ident Point3D ) (KeyValueExpr " + "(Ident y ) (UnaryExpr (BasicLit 4 ) - ) ) (KeyValueExpr (Ident z ) (BasicLit 12.3 ) ) ) ) ) ", + "Line{origin, Point3D{y: -4, z: 12.3}}"); + EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 10 ) (Ident string ) ) ) ) ", "[10]string{}"); + EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 6 ) (Ident int ) ) (BasicLit 1 ) (BasicLit 2 ) " + "(BasicLit 3 ) (BasicLit 5 ) ) ) ", + "[6]int {1, 2, 3, 5}"); + EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType nil (Ident int ) ) (BasicLit 2 ) (BasicLit 3 ) (BasicLit 5 ) " + "(BasicLit 7 ) (BasicLit 9 ) (BasicLit 2147483647 ) ) ) ", + "[]int{2, 3, 5, 7, 9, 2147483647}"); + EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 128 ) (Ident bool ) ) (KeyValueExpr (BasicLit 'a' ) " + "(Ident true ) ) (KeyValueExpr (BasicLit 'e' ) (Ident true ) ) (KeyValueExpr (BasicLit 'i' ) (Ident " + "true ) ) (KeyValueExpr (BasicLit 'o' ) (Ident true ) ) (KeyValueExpr (BasicLit 'u' ) (Ident true ) ) " + "(KeyValueExpr (BasicLit 'y' ) (Ident true ) ) ) ) ", + "[128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true}"); + EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (BasicLit 10 ) (Ident float32 ) ) (UnaryExpr (BasicLit 1 ) - ) " + "(KeyValueExpr (BasicLit 4 ) (UnaryExpr (BasicLit 0.1 ) - ) ) (UnaryExpr (BasicLit 0.1 ) - ) " + "(KeyValueExpr (BasicLit 9 ) (UnaryExpr (BasicLit 1 ) - ) ) ) ) ", + "[10]float32{-1, 4: -0.1, -0.1, 9: -1}"); +} + +TEST(GoParserTest, ParseEllipsisArray) +{ + EXPECT_PARSE( + "(ExprStmt (CompositeLit (ArrayType (Ellipsis nil ) (Ident string ) ) (BasicLit `Sat` ) (BasicLit `Sun` ) ) ) ", + "[...]string {`Sat`, `Sun`}"); + EXPECT_PARSE("(ExprStmt (CompositeLit (ArrayType (Ellipsis nil ) (Ident Point ) ) (CompositeLit nil (BasicLit 1.5 " + ") (UnaryExpr (BasicLit 3.5 ) - ) ) (CompositeLit nil (BasicLit 0 ) (BasicLit 0 ) ) ) ) ", + "[...]Point{{1.5, -3.5}, {0, 0}}"); +} + +TEST(GoParserTest, ParseMap) +{ + EXPECT_PARSE("(ExprStmt (CompositeLit (MapType (Ident string ) (Ident float32 ) ) (KeyValueExpr (BasicLit `C0` ) " + "(BasicLit 16.35 ) ) (KeyValueExpr (BasicLit `D0` ) (BasicLit 18.35 ) ) ) ) ", + "map[string]float32{`C0`: 16.35, `D0`: 18.35, }"); +} + +TEST(GoParserTest, UnaryExpr) +{ + EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) + ) ) ", "+x"); + EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) - ) ) ", "-x"); + EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) ! ) ) ", "!x"); + EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) ^ ) ) ", "^x"); + EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) & ) ) ", "&x"); + EXPECT_PARSE("(ExprStmt (UnaryExpr (Ident x ) <- ) ) ", "<-x"); + EXPECT_PARSE("(ExprStmt (StarExpr (Ident x ) ) ) ", "*x"); +} + +TEST(GoParserTest, BinaryExpr) +{ + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) || ) ) ", "a || b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) && ) ) ", "a && b"); + + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) == ) ) ", "a == b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) != ) ) ", "a != b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) < ) ) ", "a < b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) <= ) ) ", "a <= b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) > ) ) ", "a > b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) >= ) ) ", "a >= b"); + + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) + ) ) ", "a + b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) - ) ) ", "a - b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) | ) ) ", "a | b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) ^ ) ) ", "a ^ b"); + + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) * ) ) ", "a * b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) / ) ) ", "a / b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) % ) ) ", "a % b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) << ) ) ", "a << b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) >> ) ) ", "a >> b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) & ) ) ", "a & b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (Ident b ) &^ ) ) ", "a &^ b"); + + EXPECT_PARSE( + "(ExprStmt (BinaryExpr (BasicLit 23 ) (BinaryExpr (BasicLit 3 ) (IndexExpr (Ident x ) (Ident i ) ) * ) + ) ) ", + "23 + 3*x[i]"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident a ) (UnaryExpr (UnaryExpr (Ident a ) + ) + ) + ) ) ", "a + + + a"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (UnaryExpr (Ident a ) ^ ) (Ident b ) >> ) ) ", "^a >> b"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (CallExpr (Ident f ) ) (CallExpr (Ident g ) ) || ) ) ", "f() || g()"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (BinaryExpr (Ident x ) (BinaryExpr (Ident y ) (BasicLit 1 ) + ) == ) " + "(BinaryExpr (UnaryExpr (Ident chanPtr ) <- ) (BasicLit 0 ) > ) && ) ) ", + "x == y+1 && <-chanPtr > 0"); +} + +TEST(GoParserTest, PrimaryExpr) +{ + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident x ) (CallExpr (Ident f ) ) <= ) ) ", "x <= f()"); + EXPECT_PARSE("(ExprStmt (BinaryExpr (Ident s ) (BasicLit `.txt` ) + ) ) ", "(s + `.txt`)"); + EXPECT_PARSE("(ExprStmt (CallExpr (Ident f ) (BasicLit 3.1415 ) (Ident true ) ) ) ", "f(3.1415, true)"); + EXPECT_PARSE("(ExprStmt (CallExpr (Ident f ) (BasicLit 3.1415 ) (Ident a ) ... ) ) ", "f(3.1415, a...)"); + EXPECT_PARSE("(ExprStmt (IndexExpr (Ident m ) (BasicLit '1' ) ) ) ", "m['1']"); + EXPECT_PARSE("(ExprStmt (SliceExpr (Ident s ) (Ident i ) (BinaryExpr (Ident j ) (BasicLit 1 ) + ) nil 0 ) ) ", + "s[i : j + 1]"); + EXPECT_PARSE("(ExprStmt (SelectorExpr (Ident obj ) (Ident color ) ) ) ", "obj.color"); + EXPECT_PARSE("(ExprStmt (CallExpr (SelectorExpr (IndexExpr (SelectorExpr (Ident f ) (Ident p ) ) (Ident i ) ) " + "(Ident x ) ) ) ) ", + "f.p[i].x()"); +} + +TEST(GoParserTest, Conversions) +{ + EXPECT_PARSE("(ExprStmt (StarExpr (CallExpr (Ident Point ) (Ident p ) ) ) ) ", "*Point(p)"); + EXPECT_PARSE("(ExprStmt (CallExpr (StarExpr (Ident Point ) ) (Ident p ) ) ) ", "(*Point)(p)"); + EXPECT_PARSE("(ExprStmt (UnaryExpr (CallExpr (ChanType (Ident int ) 0 ) (Ident c ) ) <- ) ) ", "<-chan int(c)"); + EXPECT_PARSE("(ExprStmt (TypeAssertExpr (Ident y ) (SelectorExpr (Ident io ) (Ident Reader ) ) ) ) ", + "y.(io.Reader)"); +}