JDevlieghere created this revision. JDevlieghere added reviewers: labath, mib, l.frisken, jingham. JDevlieghere requested review of this revision.
Make it possible to run the `script` command with a different language than currently selected. $ ./bin/lldb -l python (lldb) script -l lua >>> io.stdout:write("Hello, Wolrd!\n") Hello, Wolrd! Because of the ability to pass anything after the `script` command, it is implemented as a `CommandObjectRaw`. In a first attempt I tried to change this to a `CommandObjectParsed` in order to have the existing infrastructure parse the language argument and have the script contents as the first argument. That didn't work out, first because it unconditionally removed quotes from within the script expression and second because it attempts to expand script commands between backticks. Given how easy it is to parse the language argument, I think it's warranted to keep the `CommandObjectRaw` and just do the parsing manually. https://reviews.llvm.org/D86996 Files: lldb/source/Commands/CommandObjectScript.cpp lldb/test/Shell/ScriptInterpreter/Lua/lua-python.test lldb/test/Shell/ScriptInterpreter/Lua/lua.test lldb/test/Shell/ScriptInterpreter/None/none.test lldb/test/Shell/ScriptInterpreter/Python/python.test
Index: lldb/test/Shell/ScriptInterpreter/Python/python.test =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Python/python.test @@ -0,0 +1,9 @@ +# REQUIRES: python +# RUN: %lldb --script-language python -o 'script 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 --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: SyntaxError +# INVALID-NOT: 1111 Index: lldb/test/Shell/ScriptInterpreter/None/none.test =================================================================== --- lldb/test/Shell/ScriptInterpreter/None/none.test +++ lldb/test/Shell/ScriptInterpreter/None/none.test @@ -1,2 +1,5 @@ # RUN: %lldb --script-language none -o 'script' 2>&1 | FileCheck %s # CHECK: error: the script-lang setting is set to none - scripting not available + +# RUN: %lldb -o 'script -l none foo' 2>&1 | FileCheck %s --check-prefix ERROR +# ERROR: error: the script-lang setting is set to none - scripting not available 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,5 @@ # 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 -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/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/source/Commands/CommandObjectScript.cpp =================================================================== --- lldb/source/Commands/CommandObjectScript.cpp +++ lldb/source/Commands/CommandObjectScript.cpp @@ -25,21 +25,63 @@ interpreter, "script", "Invoke the script interpreter with provided code and display any " "results. Start the interactive interpreter if no code is supplied.", - "script [<script-code>]") {} + "script [-l <script-language>] [<script-code>]") {} CommandObjectScript::~CommandObjectScript() {} +struct CommandParsed { + CommandParsed(llvm::StringRef command) + : language(llvm::None), command(command) {} + CommandParsed(llvm::Optional<ScriptLanguage> language, + llvm::StringRef command) + : language(language), command(command) {} + llvm::Optional<ScriptLanguage> language; + llvm::StringRef command; +}; + +/// Manually parse the -l <script-language> or --language <script-language> +/// argument from the command. This is necessary because CommandObjectScript is +/// an instance of CommandObjectRaw. We cannot use CommandObjectParsed because +/// it removes quotes and replace embedded script commands between backticks. +static CommandParsed ParseLanguageArgument(llvm::StringRef command) { + llvm::StringRef head; + llvm::StringRef tail = command; + + std::tie(head, tail) = tail.split(' '); + if (head != "-l" && head != "--language") + return CommandParsed(command); + + std::tie(head, tail) = tail.split(' '); + llvm::Optional<ScriptLanguage> language = + llvm::StringSwitch<llvm::Optional<ScriptLanguage>>(head.lower()) + .Case("lua", eScriptLanguageLua) + .Case("none", eScriptLanguageNone) + .Case("python", eScriptLanguagePython) + .Default(llvm::None); + + if (language) + return CommandParsed(language, tail.ltrim()); + + return CommandParsed(command); +} + bool CommandObjectScript::DoExecute(llvm::StringRef command, CommandReturnObject &result) { - if (m_interpreter.GetDebugger().GetScriptLanguage() == - lldb::eScriptLanguageNone) { + CommandParsed parsed = ParseLanguageArgument(command); + + ScriptLanguage language = + parsed.language ? *parsed.language + : m_interpreter.GetDebugger().GetScriptLanguage(); + + if (language == 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"); @@ -51,14 +93,14 @@ // up to date with it. DataVisualization::ForceUpdate(); - if (command.empty()) { + if (parsed.command.empty()) { script_interpreter->ExecuteInterpreterLoop(); result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } // We can do better when reporting the status of one-liner script execution. - if (script_interpreter->ExecuteOneLine(command, &result)) + if (script_interpreter->ExecuteOneLine(parsed.command, &result)) result.SetStatus(eReturnStatusSuccessFinishNoResult); else result.SetStatus(eReturnStatusFailed);
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits