Index: lldb/source/Commands/CommandObjectScript.h =================================================================== --- lldb/source/Commands/CommandObjectScript.h +++ lldb/source/Commands/CommandObjectScript.h @@ -17,9 +17,24 @@ public: CommandObjectScript(CommandInterpreter &interpreter); ~CommandObjectScript() override; + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + ~CommandOptions() override = default; + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + void OptionParsingStarting(ExecutionContext *execution_context) override; + llvm::ArrayRef GetDefinitions() override; + lldb::ScriptLanguage language = lldb::eScriptLanguageNone; + }; protected: bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; + +private: + CommandOptions m_options; }; } // namespace lldb_private Index: lldb/source/Commands/CommandObjectScript.cpp =================================================================== --- lldb/source/Commands/CommandObjectScript.cpp +++ lldb/source/Commands/CommandObjectScript.cpp @@ -10,36 +10,107 @@ #include "lldb/Core/Debugger.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Host/Config.h" +#include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Utility/Args.h" using namespace lldb; using namespace lldb_private; -// CommandObjectScript +static constexpr OptionEnumValueElement g_script_option_enumeration[] = { + { + eScriptLanguagePython, + "python", + "Python", + }, + { + eScriptLanguageLua, + "lua", + "Lua", + }, + { + eScriptLanguageNone, + "default", + "The default scripting language.", + }, +}; + +static constexpr OptionEnumValues ScriptOptionEnum() { + return OptionEnumValues(g_script_option_enumeration); +} + +#define LLDB_OPTIONS_script +#include "CommandOptions.inc" + +Status CommandObjectScript::CommandOptions::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'l': + language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, + eScriptLanguageNone, error); + if (!error.Success()) + error.SetErrorStringWithFormat("unrecognized value for language '%s'", + option_arg.str().c_str()); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; +} + +void CommandObjectScript::CommandOptions::OptionParsingStarting( + ExecutionContext *execution_context) { + language = lldb::eScriptLanguageNone; +} + +llvm::ArrayRef +CommandObjectScript::CommandOptions::GetDefinitions() { + return llvm::makeArrayRef(g_script_options); +} CommandObjectScript::CommandObjectScript(CommandInterpreter &interpreter) : CommandObjectRaw( interpreter, "script", "Invoke the script interpreter with provided code and display any " "results. Start the interactive interpreter if no code is supplied.", - "script []") {} + "script [--language --] []") {} CommandObjectScript::~CommandObjectScript() {} bool CommandObjectScript::DoExecute(llvm::StringRef command, CommandReturnObject &result) { - if (m_interpreter.GetDebugger().GetScriptLanguage() == - lldb::eScriptLanguageNone) { + // Try parsing the language option but when the command contains a raw part + // separated by the -- delimiter. + OptionsWithRaw raw_args(command); + if (raw_args.HasArgs()) { + if (!ParseOptions(raw_args.GetArgs(), result)) + return false; + command = raw_args.GetRawPart(); + } + + lldb::ScriptLanguage language = + (m_options.language == lldb::eScriptLanguageNone) + ? m_interpreter.GetDebugger().GetScriptLanguage() + : m_options.language; + + if (language == lldb::eScriptLanguageNone) { result.AppendError( "the script-lang setting is set to none - scripting not available"); result.SetStatus(eReturnStatusFailed); return false; } - ScriptInterpreter *script_interpreter = GetDebugger().GetScriptInterpreter(); + ScriptInterpreter *script_interpreter = + GetDebugger().GetScriptInterpreter(true, language); if (script_interpreter == nullptr) { result.AppendError("no script interpreter"); Index: lldb/source/Commands/Options.td =================================================================== --- lldb/source/Commands/Options.td +++ lldb/source/Commands/Options.td @@ -717,6 +717,12 @@ "LLDB event system.">; } +let Command = "script" in { + def script_language : Option<"language", "l">, + EnumArg<"ScriptLang", "ScriptOptionEnum()">, Desc<"Specify the scripting " + " language. If none is specific the default scripting language is used.">; +} + let Command = "source info" in { def source_info_count : Option<"count", "c">, Arg<"Count">, Desc<"The number of line entries to display.">; Index: lldb/test/Shell/ScriptInterpreter/Lua/lua-python.test =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Lua/lua-python.test @@ -0,0 +1,17 @@ +# REQUIRES: lua +# REQUIRES: python +# UNSUPPORTED: lldb-repro + +# RUN: mkdir -p %t +# RUN: cd %t +# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o a.out +# RUN: cat %s | %lldb 2>&1 | FileCheck %s +script -l lua -- +target = lldb.debugger:CreateTarget("a.out") +print("target is valid:", tostring(target:IsValid())) +lldb.debugger:SetSelectedTarget(target) +quit +# CHECK: target is valid: true +script -l python -- +print("selected target: {}".format(lldb.debugger.GetSelectedTarget())) +# CHECK: selected target: a.out Index: lldb/test/Shell/ScriptInterpreter/Lua/lua.test =================================================================== --- lldb/test/Shell/ScriptInterpreter/Lua/lua.test +++ lldb/test/Shell/ScriptInterpreter/Lua/lua.test @@ -1,3 +1,6 @@ # REQUIRES: lua -# RUN: %lldb --script-language lua -o 'script print(1000+100+10+1)' 2>&1 | FileCheck %s +# RUN: %lldb --script-language lua -o 'script -- io.stdout:write(1000+100+10+1, "\n")' 2>&1 | FileCheck %s +# RUN: %lldb --script-language lua -o 'script --language default -- io.stdout:write(1000+100+10+1, "\n")' 2>&1 | FileCheck %s +# RUN: %lldb -o 'script -l lua -- io.stdout:write(1000+100+10+1, "\n")' 2>&1 | FileCheck %s +# RUN: %lldb -o 'script --language lua -- io.stdout:write(1000+100+10+1, "\n")' 2>&1 | FileCheck %s # CHECK: 1111 Index: lldb/test/Shell/ScriptInterpreter/Python/python.test =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Python/python.test @@ -0,0 +1,12 @@ +# REQUIRES: python +# RUN: %lldb --script-language python -o 'script -- print("{}".format(1000+100+10+1))' 2>&1 | FileCheck %s +# RUN: %lldb --script-language python -o 'script --language default -- print("{}".format(1000+100+10+1))' 2>&1 | FileCheck %s +# RUN: %lldb -o 'script -l python -- print("{}".format(1000+100+10+1))' 2>&1 | FileCheck %s +# RUN: %lldb -o 'script -lpython -- print("{}".format(1000+100+10+1))' 2>&1 | FileCheck %s +# RUN: %lldb -o 'script --language python -- print("{}".format(1000+100+10+1))' 2>&1 | FileCheck %s +# RUN: %lldb -o 'script --language=python -- print("{}".format(1000+100+10+1))' 2>&1 | FileCheck %s +# CHECK: 1111 + +# RUN: %lldb -o 'script --language invalid -- print("{}".format(1000+100+10+1))' 2>&1 | FileCheck %s --check-prefix INVALID +# INVALID: error: unrecognized value for language 'invalid' +# INVALID-NOT: 1111