Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -73,6 +73,7 @@ lldbPluginProcessElfCore lldbPluginJITLoaderGDB lldbPluginExpressionParserClang + lldbPluginExpressionParserGo ) # Windows-only libraries Index: include/lldb/Expression/UserExpression.h =================================================================== --- include/lldb/Expression/UserExpression.h +++ include/lldb/Expression/UserExpression.h @@ -107,11 +107,8 @@ 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); @@ -143,12 +140,12 @@ /// @return /// A Process::Execution results value. //------------------------------------------------------------------ - lldb::ExpressionResults + virtual lldb::ExpressionResults Execute (Stream &error_stream, ExecutionContext &exe_ctx, const EvaluateExpressionOptions& options, lldb::UserExpressionSP &shared_ptr_to_me, - lldb::ExpressionVariableSP &result); + lldb::ExpressionVariableSP &result) = 0; //------------------------------------------------------------------ /// Apply the side effects of the function to program state. @@ -173,21 +170,20 @@ /// @return /// A Process::Execution results value. //------------------------------------------------------------------ - bool + 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); + 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(); } //------------------------------------------------------------------ @@ -298,23 +294,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); @@ -325,31 +304,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 @@ -380,6 +380,19 @@ GoASTContext(const GoASTContext &) = delete; const GoASTContext &operator=(const GoASTContext &) = delete; }; -} +class GoASTContextForExpr : public GoASTContext +{ + public: + GoASTContextForExpr(lldb::TargetSP target) + : m_target_wp(target) + { + } + virtual UserExpression *GetUserExpression(const char *expr, const char *expr_prefix, lldb::LanguageType language, + Expression::ResultType desired_type) override; + + private: + lldb::TargetWP m_target_wp; +}; +} #endif /* defined(__lldb__GoASTContext__) */ Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -820,6 +820,9 @@ 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 */; }; 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 */; }; @@ -2633,6 +2636,13 @@ 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 = ""; }; 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 = ""; }; @@ -5083,6 +5093,7 @@ isa = PBXGroup; children = ( 4984BA0C1B97620B008658D4 /* Clang */, + AE44FB371BB35A2E0033EB62 /* Go */, ); name = ExpressionParser; sourceTree = ""; @@ -5447,6 +5458,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 = ""; + }; AE8F624519EF3DFC00326B21 /* Go */ = { isa = PBXGroup; children = ( @@ -6298,6 +6323,7 @@ 4984BA131B978C55008658D4 /* ClangExpressionVariable.cpp in Sources */, 3F81691A1ABA2419001DA9DF /* NameMatches.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 */, @@ -6413,6 +6439,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 */, @@ -6572,6 +6599,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/UserExpression.cpp =================================================================== --- source/Expression/UserExpression.cpp +++ source/Expression/UserExpression.cpp @@ -51,36 +51,16 @@ 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) + 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,293 +150,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, result, 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; - } - - 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, 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 @@ -157,6 +157,36 @@ lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, bool generate_debug_info) 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(); + } ExpressionTypeSystemHelper * GetTypeSystemHelper () override @@ -187,15 +217,42 @@ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the environment. //------------------------------------------------------------------ + bool + PrepareToExecuteJITExpression (Stream &error_stream, + ExecutionContext &exe_ctx, + lldb::addr_t &struct_address); + void ScanContext (ExecutionContext &exe_ctx, - lldb_private::Error &err) override; + lldb_private::Error &err); bool AddInitialArguments (ExecutionContext &exe_ctx, std::vector &args, - Stream &error_stream) override; + Stream &error_stream); + + 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. + ClangUserExpressionHelper m_type_system_helper; }; Index: source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -61,6 +61,21 @@ 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), m_type_system_helper(*m_target_wp.lock().get()) { switch (m_language) @@ -81,6 +96,12 @@ ClangUserExpression::~ClangUserExpression () { + 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 @@ -613,3 +634,291 @@ return m_result_synthesizer_up.get(); } +lldb::ExpressionResults +ClangUserExpression::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 +ClangUserExpression::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, result, 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; + } + + if (result) + result->TransferAddress(); + + m_dematerializer_sp.reset(); + + return true; +} + +bool +ClangUserExpression::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; +} + + 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,2012 @@ +//===-- 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() { } + + 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(len), m_elt(elt) {} + virtual ~GoASTArrayType() { } + + const char* GetKindName() const { return "ArrayType"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eArrayType; } + + const GoASTExpr* GetLen() const { return m_len.get(); } + void SetLen(GoASTExpr* len) { m_len.reset(len); } + + const GoASTExpr* GetElt() const { return m_elt.get(); } + void SetElt(GoASTExpr* elt) { m_elt.reset(elt); } + +private: + friend class GoASTNode; + std::unique_ptr m_len; + std::unique_ptr m_elt; + + GoASTArrayType(const GoASTArrayType&) = delete; + const GoASTArrayType& operator=(const GoASTArrayType&) = delete; +}; + +class GoASTAssignStmt : public GoASTStmt +{ +public: + explicit GoASTAssignStmt(bool define) : GoASTStmt(eAssignStmt), m_define(define) {} + virtual ~GoASTAssignStmt() { } + + const char* GetKindName() const { 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) {} + virtual ~GoASTBadDecl() { } + + const char* GetKindName() const { 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) {} + virtual ~GoASTBadExpr() { } + + const char* GetKindName() const { 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) {} + virtual ~GoASTBadStmt() { } + + const char* GetKindName() const { 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) {} + virtual ~GoASTBasicLit() { } + + const char* GetKindName() const { 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(x), m_y(y), m_op(op) {} + virtual ~GoASTBinaryExpr() { } + + const char* GetKindName() const { return "BinaryExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eBinaryExpr; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + + const GoASTExpr* GetY() const { return m_y.get(); } + void SetY(GoASTExpr* y) { m_y.reset(y); } + + TokenType GetOp() const { return m_op; } + void SetOp(TokenType op) { m_op = op; } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + std::unique_ptr m_y; + TokenType m_op; + + GoASTBinaryExpr(const GoASTBinaryExpr&) = delete; + const GoASTBinaryExpr& operator=(const GoASTBinaryExpr&) = delete; +}; + +class GoASTBlockStmt : public GoASTStmt +{ +public: + GoASTBlockStmt() : GoASTStmt(eBlockStmt) {} + virtual ~GoASTBlockStmt() { } + + const char* GetKindName() const { 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) {} + virtual ~GoASTIdent() { } + + const char* GetKindName() const { 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(label), m_tok(tok) {} + virtual ~GoASTBranchStmt() { } + + const char* GetKindName() const { return "BranchStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eBranchStmt; } + + const GoASTIdent* GetLabel() const { return m_label.get(); } + void SetLabel(GoASTIdent* label) { m_label.reset(label); } + + TokenType GetTok() const { return m_tok; } + void SetTok(TokenType tok) { m_tok = tok; } + +private: + friend class GoASTNode; + std::unique_ptr m_label; + 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) {} + virtual ~GoASTCallExpr() { } + + const char* GetKindName() const { return "CallExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eCallExpr; } + + const GoASTExpr* GetFun() const { return m_fun.get(); } + void SetFun(GoASTExpr* fun) { m_fun.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; + 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) {} + virtual ~GoASTCaseClause() { } + + const char* GetKindName() const { 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(value) {} + virtual ~GoASTChanType() { } + + const char* GetKindName() const { 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.get(); } + void SetValue(GoASTExpr* value) { m_value.reset(value); } + +private: + friend class GoASTNode; + ChanDir m_dir; + std::unique_ptr m_value; + + GoASTChanType(const GoASTChanType&) = delete; + const GoASTChanType& operator=(const GoASTChanType&) = delete; +}; + +class GoASTCommClause : public GoASTStmt +{ +public: + GoASTCommClause() : GoASTStmt(eCommClause) {} + virtual ~GoASTCommClause() { } + + const char* GetKindName() const { return "CommClause"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eCommClause; } + + const GoASTStmt* GetComm() const { return m_comm.get(); } + void SetComm(GoASTStmt* comm) { m_comm.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; + std::vector > m_body; + + GoASTCommClause(const GoASTCommClause&) = delete; + const GoASTCommClause& operator=(const GoASTCommClause&) = delete; +}; + +class GoASTCompositeLit : public GoASTExpr +{ +public: + GoASTCompositeLit() : GoASTExpr(eCompositeLit) {} + virtual ~GoASTCompositeLit() { } + + const char* GetKindName() const { return "CompositeLit"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eCompositeLit; } + + const GoASTExpr* GetType() const { return m_type.get(); } + void SetType(GoASTExpr* type) { m_type.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; + 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(decl) {} + virtual ~GoASTDeclStmt() { } + + const char* GetKindName() const { return "DeclStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eDeclStmt; } + + const GoASTDecl* GetDecl() const { return m_decl.get(); } + void SetDecl(GoASTDecl* decl) { m_decl.reset(decl); } + +private: + friend class GoASTNode; + std::unique_ptr m_decl; + + GoASTDeclStmt(const GoASTDeclStmt&) = delete; + const GoASTDeclStmt& operator=(const GoASTDeclStmt&) = delete; +}; + +class GoASTDeferStmt : public GoASTStmt +{ +public: + explicit GoASTDeferStmt(GoASTCallExpr* call) : GoASTStmt(eDeferStmt), m_call(call) {} + virtual ~GoASTDeferStmt() { } + + const char* GetKindName() const { return "DeferStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eDeferStmt; } + + const GoASTCallExpr* GetCall() const { return m_call.get(); } + void SetCall(GoASTCallExpr* call) { m_call.reset(call); } + +private: + friend class GoASTNode; + std::unique_ptr m_call; + + GoASTDeferStmt(const GoASTDeferStmt&) = delete; + const GoASTDeferStmt& operator=(const GoASTDeferStmt&) = delete; +}; + +class GoASTEllipsis : public GoASTExpr +{ +public: + explicit GoASTEllipsis(GoASTExpr* elt) : GoASTExpr(eEllipsis), m_elt(elt) {} + virtual ~GoASTEllipsis() { } + + const char* GetKindName() const { return "Ellipsis"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eEllipsis; } + + const GoASTExpr* GetElt() const { return m_elt.get(); } + void SetElt(GoASTExpr* elt) { m_elt.reset(elt); } + +private: + friend class GoASTNode; + std::unique_ptr m_elt; + + GoASTEllipsis(const GoASTEllipsis&) = delete; + const GoASTEllipsis& operator=(const GoASTEllipsis&) = delete; +}; + +class GoASTEmptyStmt : public GoASTStmt +{ +public: + GoASTEmptyStmt() : GoASTStmt(eEmptyStmt) {} + virtual ~GoASTEmptyStmt() { } + + const char* GetKindName() const { 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(x) {} + virtual ~GoASTExprStmt() { } + + const char* GetKindName() const { return "ExprStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eExprStmt; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + + GoASTExprStmt(const GoASTExprStmt&) = delete; + const GoASTExprStmt& operator=(const GoASTExprStmt&) = delete; +}; + +class GoASTField : public GoASTNode +{ +public: + GoASTField() : GoASTNode(eField) {} + virtual ~GoASTField() { } + + const char* GetKindName() const { 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.get(); } + void SetType(GoASTExpr* type) { m_type.reset(type); } + + const GoASTBasicLit* GetTag() const { return m_tag.get(); } + void SetTag(GoASTBasicLit* tag) { m_tag.reset(tag); } + +private: + friend class GoASTNode; + std::vector > m_names; + std::unique_ptr m_type; + std::unique_ptr m_tag; + + GoASTField(const GoASTField&) = delete; + const GoASTField& operator=(const GoASTField&) = delete; +}; + +class GoASTFieldList : public GoASTNode +{ +public: + GoASTFieldList() : GoASTNode(eFieldList) {} + virtual ~GoASTFieldList() { } + + const char* GetKindName() const { 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(init), m_cond(cond), m_post(post), m_body(body) {} + virtual ~GoASTForStmt() { } + + const char* GetKindName() const { return "ForStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eForStmt; } + + const GoASTStmt* GetInit() const { return m_init.get(); } + void SetInit(GoASTStmt* init) { m_init.reset(init); } + + const GoASTExpr* GetCond() const { return m_cond.get(); } + void SetCond(GoASTExpr* cond) { m_cond.reset(cond); } + + const GoASTStmt* GetPost() const { return m_post.get(); } + void SetPost(GoASTStmt* post) { m_post.reset(post); } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + +private: + friend class GoASTNode; + std::unique_ptr m_init; + std::unique_ptr m_cond; + std::unique_ptr m_post; + std::unique_ptr m_body; + + GoASTForStmt(const GoASTForStmt&) = delete; + const GoASTForStmt& operator=(const GoASTForStmt&) = delete; +}; + +class GoASTFuncType : public GoASTExpr +{ +public: + GoASTFuncType(GoASTFieldList* params, GoASTFieldList* results) : GoASTExpr(eFuncType), m_params(params), m_results(results) {} + virtual ~GoASTFuncType() { } + + const char* GetKindName() const { return "FuncType"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eFuncType; } + + const GoASTFieldList* GetParams() const { return m_params.get(); } + void SetParams(GoASTFieldList* params) { m_params.reset(params); } + + const GoASTFieldList* GetResults() const { return m_results.get(); } + void SetResults(GoASTFieldList* results) { m_results.reset(results); } + +private: + friend class GoASTNode; + std::unique_ptr m_params; + std::unique_ptr m_results; + + 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(recv), m_name(name), m_type(type), m_body(body) {} + virtual ~GoASTFuncDecl() { } + + const char* GetKindName() const { return "FuncDecl"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eFuncDecl; } + + const GoASTFieldList* GetRecv() const { return m_recv.get(); } + void SetRecv(GoASTFieldList* recv) { m_recv.reset(recv); } + + const GoASTIdent* GetName() const { return m_name.get(); } + void SetName(GoASTIdent* name) { m_name.reset(name); } + + const GoASTFuncType* GetType() const { return m_type.get(); } + void SetType(GoASTFuncType* type) { m_type.reset(type); } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + +private: + friend class GoASTNode; + std::unique_ptr m_recv; + std::unique_ptr m_name; + std::unique_ptr m_type; + std::unique_ptr m_body; + + GoASTFuncDecl(const GoASTFuncDecl&) = delete; + const GoASTFuncDecl& operator=(const GoASTFuncDecl&) = delete; +}; + +class GoASTFuncLit : public GoASTExpr +{ +public: + GoASTFuncLit(GoASTFuncType* type, GoASTBlockStmt* body) : GoASTExpr(eFuncLit), m_type(type), m_body(body) {} + virtual ~GoASTFuncLit() { } + + const char* GetKindName() const { return "FuncLit"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eFuncLit; } + + const GoASTFuncType* GetType() const { return m_type.get(); } + void SetType(GoASTFuncType* type) { m_type.reset(type); } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + +private: + friend class GoASTNode; + std::unique_ptr m_type; + std::unique_ptr m_body; + + GoASTFuncLit(const GoASTFuncLit&) = delete; + const GoASTFuncLit& operator=(const GoASTFuncLit&) = delete; +}; + +class GoASTGenDecl : public GoASTDecl +{ +public: + explicit GoASTGenDecl(TokenType tok) : GoASTDecl(eGenDecl), m_tok(tok) {} + virtual ~GoASTGenDecl() { } + + const char* GetKindName() const { 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(call) {} + virtual ~GoASTGoStmt() { } + + const char* GetKindName() const { return "GoStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eGoStmt; } + + const GoASTCallExpr* GetCall() const { return m_call.get(); } + void SetCall(GoASTCallExpr* call) { m_call.reset(call); } + +private: + friend class GoASTNode; + std::unique_ptr m_call; + + 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(init), m_cond(cond), m_body(body), m_els(els) {} + virtual ~GoASTIfStmt() { } + + const char* GetKindName() const { return "IfStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eIfStmt; } + + const GoASTStmt* GetInit() const { return m_init.get(); } + void SetInit(GoASTStmt* init) { m_init.reset(init); } + + const GoASTExpr* GetCond() const { return m_cond.get(); } + void SetCond(GoASTExpr* cond) { m_cond.reset(cond); } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + + const GoASTStmt* GetEls() const { return m_els.get(); } + void SetEls(GoASTStmt* els) { m_els.reset(els); } + +private: + friend class GoASTNode; + std::unique_ptr m_init; + std::unique_ptr m_cond; + std::unique_ptr m_body; + std::unique_ptr m_els; + + GoASTIfStmt(const GoASTIfStmt&) = delete; + const GoASTIfStmt& operator=(const GoASTIfStmt&) = delete; +}; + +class GoASTImportSpec : public GoASTSpec +{ +public: + GoASTImportSpec(GoASTIdent* name, GoASTBasicLit* path) : GoASTSpec(eImportSpec), m_name(name), m_path(path) {} + virtual ~GoASTImportSpec() { } + + const char* GetKindName() const { return "ImportSpec"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eImportSpec; } + + const GoASTIdent* GetName() const { return m_name.get(); } + void SetName(GoASTIdent* name) { m_name.reset(name); } + + const GoASTBasicLit* GetPath() const { return m_path.get(); } + void SetPath(GoASTBasicLit* path) { m_path.reset(path); } + +private: + friend class GoASTNode; + std::unique_ptr m_name; + std::unique_ptr m_path; + + GoASTImportSpec(const GoASTImportSpec&) = delete; + const GoASTImportSpec& operator=(const GoASTImportSpec&) = delete; +}; + +class GoASTIncDecStmt : public GoASTStmt +{ +public: + GoASTIncDecStmt(GoASTExpr* x, TokenType tok) : GoASTStmt(eIncDecStmt), m_x(x), m_tok(tok) {} + virtual ~GoASTIncDecStmt() { } + + const char* GetKindName() const { return "IncDecStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eIncDecStmt; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + + TokenType GetTok() const { return m_tok; } + void SetTok(TokenType tok) { m_tok = tok; } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + 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(x), m_index(index) {} + virtual ~GoASTIndexExpr() { } + + const char* GetKindName() const { return "IndexExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eIndexExpr; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + + const GoASTExpr* GetIndex() const { return m_index.get(); } + void SetIndex(GoASTExpr* index) { m_index.reset(index); } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + std::unique_ptr m_index; + + GoASTIndexExpr(const GoASTIndexExpr&) = delete; + const GoASTIndexExpr& operator=(const GoASTIndexExpr&) = delete; +}; + +class GoASTInterfaceType : public GoASTExpr +{ +public: + explicit GoASTInterfaceType(GoASTFieldList* methods) : GoASTExpr(eInterfaceType), m_methods(methods) {} + virtual ~GoASTInterfaceType() { } + + const char* GetKindName() const { return "InterfaceType"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eInterfaceType; } + + const GoASTFieldList* GetMethods() const { return m_methods.get(); } + void SetMethods(GoASTFieldList* methods) { m_methods.reset(methods); } + +private: + friend class GoASTNode; + std::unique_ptr m_methods; + + GoASTInterfaceType(const GoASTInterfaceType&) = delete; + const GoASTInterfaceType& operator=(const GoASTInterfaceType&) = delete; +}; + +class GoASTKeyValueExpr : public GoASTExpr +{ +public: + GoASTKeyValueExpr(GoASTExpr* key, GoASTExpr* value) : GoASTExpr(eKeyValueExpr), m_key(key), m_value(value) {} + virtual ~GoASTKeyValueExpr() { } + + const char* GetKindName() const { return "KeyValueExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eKeyValueExpr; } + + const GoASTExpr* GetKey() const { return m_key.get(); } + void SetKey(GoASTExpr* key) { m_key.reset(key); } + + const GoASTExpr* GetValue() const { return m_value.get(); } + void SetValue(GoASTExpr* value) { m_value.reset(value); } + +private: + friend class GoASTNode; + std::unique_ptr m_key; + std::unique_ptr m_value; + + GoASTKeyValueExpr(const GoASTKeyValueExpr&) = delete; + const GoASTKeyValueExpr& operator=(const GoASTKeyValueExpr&) = delete; +}; + +class GoASTLabeledStmt : public GoASTStmt +{ +public: + GoASTLabeledStmt(GoASTIdent* label, GoASTStmt* stmt) : GoASTStmt(eLabeledStmt), m_label(label), m_stmt(stmt) {} + virtual ~GoASTLabeledStmt() { } + + const char* GetKindName() const { return "LabeledStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eLabeledStmt; } + + const GoASTIdent* GetLabel() const { return m_label.get(); } + void SetLabel(GoASTIdent* label) { m_label.reset(label); } + + const GoASTStmt* GetStmt() const { return m_stmt.get(); } + void SetStmt(GoASTStmt* stmt) { m_stmt.reset(stmt); } + +private: + friend class GoASTNode; + std::unique_ptr m_label; + std::unique_ptr m_stmt; + + GoASTLabeledStmt(const GoASTLabeledStmt&) = delete; + const GoASTLabeledStmt& operator=(const GoASTLabeledStmt&) = delete; +}; + +class GoASTMapType : public GoASTExpr +{ +public: + GoASTMapType(GoASTExpr* key, GoASTExpr* value) : GoASTExpr(eMapType), m_key(key), m_value(value) {} + virtual ~GoASTMapType() { } + + const char* GetKindName() const { return "MapType"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eMapType; } + + const GoASTExpr* GetKey() const { return m_key.get(); } + void SetKey(GoASTExpr* key) { m_key.reset(key); } + + const GoASTExpr* GetValue() const { return m_value.get(); } + void SetValue(GoASTExpr* value) { m_value.reset(value); } + +private: + friend class GoASTNode; + std::unique_ptr m_key; + std::unique_ptr m_value; + + GoASTMapType(const GoASTMapType&) = delete; + const GoASTMapType& operator=(const GoASTMapType&) = delete; +}; + +class GoASTParenExpr : public GoASTExpr +{ +public: + explicit GoASTParenExpr(GoASTExpr* x) : GoASTExpr(eParenExpr), m_x(x) {} + virtual ~GoASTParenExpr() { } + + const char* GetKindName() const { return "ParenExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eParenExpr; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + + 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(key), m_value(value), m_define(define), m_x(x), m_body(body) {} + virtual ~GoASTRangeStmt() { } + + const char* GetKindName() const { return "RangeStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eRangeStmt; } + + const GoASTExpr* GetKey() const { return m_key.get(); } + void SetKey(GoASTExpr* key) { m_key.reset(key); } + + const GoASTExpr* GetValue() const { return m_value.get(); } + void SetValue(GoASTExpr* value) { m_value.reset(value); } + + bool GetDefine() const { return m_define; } + void SetDefine(bool define) { m_define = define; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + +private: + friend class GoASTNode; + std::unique_ptr m_key; + std::unique_ptr m_value; + bool m_define; + std::unique_ptr m_x; + std::unique_ptr m_body; + + GoASTRangeStmt(const GoASTRangeStmt&) = delete; + const GoASTRangeStmt& operator=(const GoASTRangeStmt&) = delete; +}; + +class GoASTReturnStmt : public GoASTStmt +{ +public: + GoASTReturnStmt() : GoASTStmt(eReturnStmt) {} + virtual ~GoASTReturnStmt() { } + + const char* GetKindName() const { 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(body) {} + virtual ~GoASTSelectStmt() { } + + const char* GetKindName() const { return "SelectStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eSelectStmt; } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + +private: + friend class GoASTNode; + std::unique_ptr m_body; + + GoASTSelectStmt(const GoASTSelectStmt&) = delete; + const GoASTSelectStmt& operator=(const GoASTSelectStmt&) = delete; +}; + +class GoASTSelectorExpr : public GoASTExpr +{ +public: + GoASTSelectorExpr(GoASTExpr* x, GoASTIdent* sel) : GoASTExpr(eSelectorExpr), m_x(x), m_sel(sel) {} + virtual ~GoASTSelectorExpr() { } + + const char* GetKindName() const { return "SelectorExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eSelectorExpr; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + + const GoASTIdent* GetSel() const { return m_sel.get(); } + void SetSel(GoASTIdent* sel) { m_sel.reset(sel); } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + std::unique_ptr m_sel; + + GoASTSelectorExpr(const GoASTSelectorExpr&) = delete; + const GoASTSelectorExpr& operator=(const GoASTSelectorExpr&) = delete; +}; + +class GoASTSendStmt : public GoASTStmt +{ +public: + GoASTSendStmt(GoASTExpr* chan, GoASTExpr* value) : GoASTStmt(eSendStmt), m_chan(chan), m_value(value) {} + virtual ~GoASTSendStmt() { } + + const char* GetKindName() const { return "SendStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eSendStmt; } + + const GoASTExpr* GetChan() const { return m_chan.get(); } + void SetChan(GoASTExpr* chan) { m_chan.reset(chan); } + + const GoASTExpr* GetValue() const { return m_value.get(); } + void SetValue(GoASTExpr* value) { m_value.reset(value); } + +private: + friend class GoASTNode; + std::unique_ptr m_chan; + std::unique_ptr m_value; + + 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(x), m_low(low), m_high(high), m_max(max), m_slice3(slice3) {} + virtual ~GoASTSliceExpr() { } + + const char* GetKindName() const { return "SliceExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eSliceExpr; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + + const GoASTExpr* GetLow() const { return m_low.get(); } + void SetLow(GoASTExpr* low) { m_low.reset(low); } + + const GoASTExpr* GetHigh() const { return m_high.get(); } + void SetHigh(GoASTExpr* high) { m_high.reset(high); } + + const GoASTExpr* GetMax() const { return m_max.get(); } + void SetMax(GoASTExpr* max) { m_max.reset(max); } + + bool GetSlice3() const { return m_slice3; } + void SetSlice3(bool slice3) { m_slice3 = slice3; } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + std::unique_ptr m_low; + std::unique_ptr m_high; + std::unique_ptr m_max; + 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(x) {} + virtual ~GoASTStarExpr() { } + + const char* GetKindName() const { return "StarExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eStarExpr; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + + GoASTStarExpr(const GoASTStarExpr&) = delete; + const GoASTStarExpr& operator=(const GoASTStarExpr&) = delete; +}; + +class GoASTStructType : public GoASTExpr +{ +public: + explicit GoASTStructType(GoASTFieldList* fields) : GoASTExpr(eStructType), m_fields(fields) {} + virtual ~GoASTStructType() { } + + const char* GetKindName() const { return "StructType"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eStructType; } + + const GoASTFieldList* GetFields() const { return m_fields.get(); } + void SetFields(GoASTFieldList* fields) { m_fields.reset(fields); } + +private: + friend class GoASTNode; + std::unique_ptr m_fields; + + 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(init), m_tag(tag), m_body(body) {} + virtual ~GoASTSwitchStmt() { } + + const char* GetKindName() const { return "SwitchStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eSwitchStmt; } + + const GoASTStmt* GetInit() const { return m_init.get(); } + void SetInit(GoASTStmt* init) { m_init.reset(init); } + + const GoASTExpr* GetTag() const { return m_tag.get(); } + void SetTag(GoASTExpr* tag) { m_tag.reset(tag); } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + +private: + friend class GoASTNode; + std::unique_ptr m_init; + std::unique_ptr m_tag; + std::unique_ptr m_body; + + GoASTSwitchStmt(const GoASTSwitchStmt&) = delete; + const GoASTSwitchStmt& operator=(const GoASTSwitchStmt&) = delete; +}; + +class GoASTTypeAssertExpr : public GoASTExpr +{ +public: + GoASTTypeAssertExpr(GoASTExpr* x, GoASTExpr* type) : GoASTExpr(eTypeAssertExpr), m_x(x), m_type(type) {} + virtual ~GoASTTypeAssertExpr() { } + + const char* GetKindName() const { return "TypeAssertExpr"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eTypeAssertExpr; } + + const GoASTExpr* GetX() const { return m_x.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + + const GoASTExpr* GetType() const { return m_type.get(); } + void SetType(GoASTExpr* type) { m_type.reset(type); } + +private: + friend class GoASTNode; + std::unique_ptr m_x; + std::unique_ptr m_type; + + GoASTTypeAssertExpr(const GoASTTypeAssertExpr&) = delete; + const GoASTTypeAssertExpr& operator=(const GoASTTypeAssertExpr&) = delete; +}; + +class GoASTTypeSpec : public GoASTSpec +{ +public: + GoASTTypeSpec(GoASTIdent* name, GoASTExpr* type) : GoASTSpec(eTypeSpec), m_name(name), m_type(type) {} + virtual ~GoASTTypeSpec() { } + + const char* GetKindName() const { return "TypeSpec"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eTypeSpec; } + + const GoASTIdent* GetName() const { return m_name.get(); } + void SetName(GoASTIdent* name) { m_name.reset(name); } + + const GoASTExpr* GetType() const { return m_type.get(); } + void SetType(GoASTExpr* type) { m_type.reset(type); } + +private: + friend class GoASTNode; + std::unique_ptr m_name; + std::unique_ptr m_type; + + 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(init), m_assign(assign), m_body(body) {} + virtual ~GoASTTypeSwitchStmt() { } + + const char* GetKindName() const { return "TypeSwitchStmt"; } + + static bool + classof(const GoASTNode* n) { return n->GetKind() == eTypeSwitchStmt; } + + const GoASTStmt* GetInit() const { return m_init.get(); } + void SetInit(GoASTStmt* init) { m_init.reset(init); } + + const GoASTStmt* GetAssign() const { return m_assign.get(); } + void SetAssign(GoASTStmt* assign) { m_assign.reset(assign); } + + const GoASTBlockStmt* GetBody() const { return m_body.get(); } + void SetBody(GoASTBlockStmt* body) { m_body.reset(body); } + +private: + friend class GoASTNode; + std::unique_ptr m_init; + std::unique_ptr m_assign; + std::unique_ptr m_body; + + 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(x) {} + virtual ~GoASTUnaryExpr() { } + + const char* GetKindName() const { 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.get(); } + void SetX(GoASTExpr* x) { m_x.reset(x); } + +private: + friend class GoASTNode; + TokenType m_op; + std::unique_ptr m_x; + + GoASTUnaryExpr(const GoASTUnaryExpr&) = delete; + const GoASTUnaryExpr& operator=(const GoASTUnaryExpr&) = delete; +}; + +class GoASTValueSpec : public GoASTSpec +{ +public: + GoASTValueSpec() : GoASTSpec(eValueSpec) {} + virtual ~GoASTValueSpec() { } + + const char* GetKindName() const { 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.get(); } + void SetType(GoASTExpr* type) { m_type.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; + 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.get()); + v(n->m_elt.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.get()); + v(n->m_y.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.get()); + return; + } + case eCallExpr: + { + GoASTCallExpr* n = llvm::cast(this); + (void)n; + v(n->m_fun.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.get()); + return; + } + case eCommClause: + { + GoASTCommClause* n = llvm::cast(this); + (void)n; + v(n->m_comm.get()); + for (auto& e : n->m_body) { v(e.get()); } + return; + } + case eCompositeLit: + { + GoASTCompositeLit* n = llvm::cast(this); + (void)n; + v(n->m_type.get()); + for (auto& e : n->m_elts) { v(e.get()); } + return; + } + case eDeclStmt: + { + GoASTDeclStmt* n = llvm::cast(this); + (void)n; + v(n->m_decl.get()); + return; + } + case eDeferStmt: + { + GoASTDeferStmt* n = llvm::cast(this); + (void)n; + v(n->m_call.get()); + return; + } + case eEllipsis: + { + GoASTEllipsis* n = llvm::cast(this); + (void)n; + v(n->m_elt.get()); + return; + } + case eExprStmt: + { + GoASTExprStmt* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + return; + } + case eField: + { + GoASTField* n = llvm::cast(this); + (void)n; + for (auto& e : n->m_names) { v(e.get()); } + v(n->m_type.get()); + v(n->m_tag.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.get()); + v(n->m_cond.get()); + v(n->m_post.get()); + v(n->m_body.get()); + return; + } + case eFuncType: + { + GoASTFuncType* n = llvm::cast(this); + (void)n; + v(n->m_params.get()); + v(n->m_results.get()); + return; + } + case eFuncDecl: + { + GoASTFuncDecl* n = llvm::cast(this); + (void)n; + v(n->m_recv.get()); + v(n->m_name.get()); + v(n->m_type.get()); + v(n->m_body.get()); + return; + } + case eFuncLit: + { + GoASTFuncLit* n = llvm::cast(this); + (void)n; + v(n->m_type.get()); + v(n->m_body.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.get()); + return; + } + case eIfStmt: + { + GoASTIfStmt* n = llvm::cast(this); + (void)n; + v(n->m_init.get()); + v(n->m_cond.get()); + v(n->m_body.get()); + v(n->m_els.get()); + return; + } + case eImportSpec: + { + GoASTImportSpec* n = llvm::cast(this); + (void)n; + v(n->m_name.get()); + v(n->m_path.get()); + return; + } + case eIncDecStmt: + { + GoASTIncDecStmt* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + return; + } + case eIndexExpr: + { + GoASTIndexExpr* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + v(n->m_index.get()); + return; + } + case eInterfaceType: + { + GoASTInterfaceType* n = llvm::cast(this); + (void)n; + v(n->m_methods.get()); + return; + } + case eKeyValueExpr: + { + GoASTKeyValueExpr* n = llvm::cast(this); + (void)n; + v(n->m_key.get()); + v(n->m_value.get()); + return; + } + case eLabeledStmt: + { + GoASTLabeledStmt* n = llvm::cast(this); + (void)n; + v(n->m_label.get()); + v(n->m_stmt.get()); + return; + } + case eMapType: + { + GoASTMapType* n = llvm::cast(this); + (void)n; + v(n->m_key.get()); + v(n->m_value.get()); + return; + } + case eParenExpr: + { + GoASTParenExpr* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + return; + } + case eRangeStmt: + { + GoASTRangeStmt* n = llvm::cast(this); + (void)n; + v(n->m_key.get()); + v(n->m_value.get()); + v(n->m_x.get()); + v(n->m_body.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.get()); + return; + } + case eSelectorExpr: + { + GoASTSelectorExpr* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + v(n->m_sel.get()); + return; + } + case eSendStmt: + { + GoASTSendStmt* n = llvm::cast(this); + (void)n; + v(n->m_chan.get()); + v(n->m_value.get()); + return; + } + case eSliceExpr: + { + GoASTSliceExpr* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + v(n->m_low.get()); + v(n->m_high.get()); + v(n->m_max.get()); + return; + } + case eStarExpr: + { + GoASTStarExpr* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + return; + } + case eStructType: + { + GoASTStructType* n = llvm::cast(this); + (void)n; + v(n->m_fields.get()); + return; + } + case eSwitchStmt: + { + GoASTSwitchStmt* n = llvm::cast(this); + (void)n; + v(n->m_init.get()); + v(n->m_tag.get()); + v(n->m_body.get()); + return; + } + case eTypeAssertExpr: + { + GoASTTypeAssertExpr* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + v(n->m_type.get()); + return; + } + case eTypeSpec: + { + GoASTTypeSpec* n = llvm::cast(this); + (void)n; + v(n->m_name.get()); + v(n->m_type.get()); + return; + } + case eTypeSwitchStmt: + { + GoASTTypeSwitchStmt* n = llvm::cast(this); + (void)n; + v(n->m_init.get()); + v(n->m_assign.get()); + v(n->m_body.get()); + return; + } + case eUnaryExpr: + { + GoASTUnaryExpr* n = llvm::cast(this); + (void)n; + v(n->m_x.get()); + return; + } + case eValueSpec: + { + GoASTValueSpec* n = llvm::cast(this); + (void)n; + for (auto& e : n->m_names) { v(e.get()); } + v(n->m_type.get()); + for (auto& e : n->m_values) { v(e.get()); } + return; + } + + default: + break; + } +} + +} // namespace lldb_private + +#endif + Index: source/Plugins/ExpressionParser/Go/GoLexer.h =================================================================== --- /dev/null +++ source/Plugins/ExpressionParser/Go/GoLexer.h @@ -0,0 +1,187 @@ +//===-- 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,375 @@ +//===-- 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,144 @@ +//===-- 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,1036 @@ +//===-- 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,96 @@ +//===-- 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,683 @@ +//===-- 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,313 @@ +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") + + +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) + addConstructor(name, parent, children) + childClasses.write(""" + const char* GetKindName() const { 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 addConstructor(name, parent, children): + childNames = [children[i] for i in xrange(0, len(children), 2)] + childTypes = [children[i] for i in xrange(1, len(children), 2)] + if len(childTypes) != len(childNames): + raise Exception("Invalid children for %s: %s" % (name, children)) + for x in childTypes: + if x.startswith("[]"): + filteredChildNames = [] + filteredChildTypes = [] + for i in xrange(len(childTypes)): + if isValueType(childTypes[i]): + filteredChildNames.append(childNames[i]) + filteredChildTypes.append(childTypes[i]) + childNames = filteredChildNames + childTypes = filteredChildTypes + break + childClasses.write(' ') + if len(childNames) == 1: + childClasses.write('explicit ') + childClasses.write('GoAST%s(' % name) + for i in xrange(len(childNames)): + if i > 0: + childClasses.write(', ') + t = childTypes[i] + if isValueType(t): + childClasses.write(t) + else: + t = "GoAST" + t + childClasses.write('%s*' % t) + childClasses.write(' ') + childClasses.write(childNames[i]) + childClasses.write(') : GoAST%s(e%s)' % (parent, name)) + for n in childNames: + childClasses.write(', ') + childClasses.write('m_%(name)s(%(name)s)' %{'name':n}) + childClasses.write(""" {} + virtual ~GoAST%s() { } +""" % name) + + +def addChildren(name, children): + if len(children) == 0: + return + childNames = [children[i] for i in xrange(0, len(children), 2)] + childTypes = [children[i] for i in xrange(1, len(children), 2)] + varTypes = [] + walker.write(""" + case e%(n)s: + { + GoAST%(n)s* n = llvm::cast(this); + (void)n;""" % {'n':name}) + for i in xrange(len(childNames)): + t = childTypes[i] + vname = childNames[i] + tname = vname.title() + + if t.startswith('[]'): + t = t[2:] + varTypes.append('std::vector >' % t) + childClasses.write(""" + size_t Num%(title)s() const { return m_%(var)s.size(); } + const %(type)s* Get%(title)s(int i) const { return m_%(var)s[i].get(); } + void Add%(title)s(%(type)s* %(var)s) { m_%(var)s.push_back(std::unique_ptr<%(type)s>(%(var)s)); } +""" % {'type':"GoAST%s" % t, 'title': tname, 'var': vname}) + walker.write(""" + for (auto& e : n->m_%s) { v(e.get()); }""" % vname) + else: + const = '' + get = '' + set = '' + if isValueType(t): + varTypes.append(t) + set = 'm_%(n)s = %(n)s' % {'n': vname} + else: + t = 'GoAST' + t + varTypes.append('std::unique_ptr<%s>' % t) + t = t + '*' + const = 'const ' + get = '.get()' + set = 'm_%(n)s.reset(%(n)s)' % {'n': vname} + walker.write(""" + v(n->m_%s.get());""" % vname) + childClasses.write(""" + %(const)s%(type)s Get%(title)s() const { return m_%(var)s%(get)s; } + void Set%(title)s(%(type)s %(var)s) { %(set)s; } +""" % {'const':const, 'title': tname, 'var': vname, 'get': get, 'set': set, 'type': t}) + childClasses.write('\nprivate:\n friend class GoASTNode;\n') + walker.write(""" + return; + }""") + for i in xrange(len(childNames)): + t = varTypes[i] + name = childNames[i] + childClasses.write(' %s m_%s;\n' %(t, name)) + + +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 "lldb/Expression/GoLexer.h" +#include "llvm/Support/Casting.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() { } + + 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""" + default: + break; + } +} + +} // namespace lldb_private + +#endif +""" Index: source/Symbol/GoASTContext.cpp =================================================================== --- source/Symbol/GoASTContext.cpp +++ source/Symbol/GoASTContext.cpp @@ -22,7 +22,9 @@ #include "lldb/Symbol/GoASTContext.h" #include "lldb/Symbol/Type.h" #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; @@ -199,7 +201,7 @@ }; GoStruct(int kind, const ConstString &name, int64_t byte_size) - : GoType(kind, name) + : GoType(kind == 0 ? KIND_STRUCT : kind, name) , m_is_complete(false) , m_byte_size(byte_size) { @@ -394,6 +396,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) @@ -563,7 +569,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; @@ -1044,6 +1051,11 @@ { return array->GetLength(); } + else if (t->IsTypedef()) + { + return t->GetElementType().GetNumChildren(omit_empty_base_classes); + } + return GetNumFields(type); } @@ -1184,6 +1196,9 @@ uint32_t GoASTContext::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes) { + if (!type || !GetCompleteType(type)) + return UINT_MAX; + GoType *t = static_cast(type); GoStruct *s = t->GetStruct(); if (s) @@ -1468,3 +1483,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 @@ -43,6 +43,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" @@ -1925,6 +1927,11 @@ m_scratch_type_system_map[language].reset(GetScratchClangASTContextImpl()); return m_scratch_type_system_map[language].get(); } + else if (eLanguageTypeGo == language) + { + m_scratch_type_system_map[language].reset(new GoASTContextForExpr(shared_from_this())); + return m_scratch_type_system_map[language].get(); + } return nullptr; } @@ -1935,13 +1942,8 @@ TypeSystem *type_system = GetScratchTypeSystemForLanguage(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(Utility) 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,221 @@ +//===-- 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)"); +}