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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits