[Lldb-commits] [lldb] 2861324 - [lldb/Lua] Implement a Simple Lua Script Interpreter Prototype
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Fri Dec 20 11:20:23 PST 2019
Author: Jonas Devlieghere
Date: 2019-12-20T11:19:47-08:00
New Revision: 2861324208e13846eb306f01b32448f94177cc3b
URL: https://github.com/llvm/llvm-project/commit/2861324208e13846eb306f01b32448f94177cc3b
DIFF: https://github.com/llvm/llvm-project/commit/2861324208e13846eb306f01b32448f94177cc3b.diff
LOG: [lldb/Lua] Implement a Simple Lua Script Interpreter Prototype
This implements a very elementary Lua script interpreter. It supports
running a single command as well as running interactively. It uses
editline if available. It's still missing a bunch of stuff though. Some
things that I intentionally ingored for now are that I/O isn't properly
hooked up (so every print goes to stdout) and the non-editline support
which is not handling a bunch of corner cases. The latter is a matter of
reusing existing code in the Python interpreter.
Discussion on the mailing list:
http://lists.llvm.org/pipermail/lldb-dev/2019-December/015812.html
Differential revision: https://reviews.llvm.org/D71234
Added:
lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
lldb/test/Shell/ScriptInterpreter/Lua/lua.test
lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp
lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp
Modified:
lldb/cmake/modules/LLDBConfig.cmake
lldb/include/lldb/Core/IOHandler.h
lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
lldb/test/CMakeLists.txt
lldb/test/Shell/lit.cfg.py
lldb/test/Shell/lit.site.cfg.py.in
lldb/unittests/ScriptInterpreter/CMakeLists.txt
Removed:
################################################################################
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index 3424cd89cb79..16465ded0522 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -113,6 +113,9 @@ if ((NOT MSVC) OR MSVC12)
add_definitions( -DHAVE_ROUND )
endif()
+if (LLDB_ENABLE_LUA)
+ find_package(Lua REQUIRED)
+endif()
if (LLDB_ENABLE_LIBEDIT)
find_package(LibEdit REQUIRED)
diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h
index cf00329f7a0b..9ab5eaaecb66 100644
--- a/lldb/include/lldb/Core/IOHandler.h
+++ b/lldb/include/lldb/Core/IOHandler.h
@@ -52,6 +52,7 @@ class IOHandler {
REPL,
ProcessIO,
PythonInterpreter,
+ LuaInterpreter,
PythonCode,
Other
};
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
index 51161638a3d0..498bd9783951 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
@@ -1,7 +1,11 @@
add_lldb_library(lldbPluginScriptInterpreterLua PLUGIN
+ Lua.cpp
ScriptInterpreterLua.cpp
LINK_LIBS
lldbCore
lldbInterpreter
- )
\ No newline at end of file
+ )
+
+target_include_directories(lldbPluginScriptInterpreterLua PUBLIC ${LUA_INCLUDE_DIR})
+target_link_libraries(lldbPluginScriptInterpreterLua INTERFACE ${LUA_LIBRARIES})
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
new file mode 100644
index 000000000000..a908ef086735
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp
@@ -0,0 +1,27 @@
+//===-- Lua.cpp -----------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lua.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace lldb_private;
+
+llvm::Error Lua::Run(llvm::StringRef buffer) {
+ int error =
+ luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||
+ lua_pcall(m_lua_state, 0, 0, 0);
+ if (!error)
+ return llvm::Error::success();
+
+ llvm::Error e = llvm::make_error<llvm::StringError>(
+ llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
+ llvm::inconvertibleErrorCode());
+ // Pop error message from the stack.
+ lua_pop(m_lua_state, 1);
+ return e;
+}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
new file mode 100644
index 000000000000..50b7ade4dc46
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h
@@ -0,0 +1,39 @@
+//===-- ScriptInterpreterLua.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Lua_h_
+#define liblldb_Lua_h_
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include "lua.hpp"
+
+namespace lldb_private {
+
+class Lua {
+public:
+ Lua() : m_lua_state(luaL_newstate()) {
+ assert(m_lua_state);
+ luaL_openlibs(m_lua_state);
+ }
+
+ ~Lua() {
+ assert(m_lua_state);
+ luaL_openlibs(m_lua_state);
+ }
+
+ llvm::Error Run(llvm::StringRef buffer);
+
+private:
+ lua_State *m_lua_state;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Lua_h_
diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
index 78aa91a6959e..b3f1689909fd 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -7,35 +7,73 @@
//===----------------------------------------------------------------------===//
#include "ScriptInterpreterLua.h"
+#include "Lua.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StringList.h"
-
-#include "llvm/Support/Threading.h"
-
-#include <mutex>
+#include "lldb/Utility/Timer.h"
using namespace lldb;
using namespace lldb_private;
+class IOHandlerLuaInterpreter : public IOHandlerDelegate,
+ public IOHandlerEditline {
+public:
+ IOHandlerLuaInterpreter(Debugger &debugger)
+ : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua",
+ ">>> ", "..> ", true, debugger.GetUseColor(), 0,
+ *this, nullptr),
+ m_lua() {}
+
+ void IOHandlerInputComplete(IOHandler &io_handler,
+ std::string &data) override {
+ if (llvm::Error error = m_lua.Run(data)) {
+ *GetOutputStreamFileSP() << llvm::toString(std::move(error));
+ }
+ }
+
+private:
+ Lua m_lua;
+};
+
ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger)
: ScriptInterpreter(debugger, eScriptLanguageLua) {}
ScriptInterpreterLua::~ScriptInterpreterLua() {}
bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command,
- CommandReturnObject *,
- const ExecuteScriptOptions &) {
- m_debugger.GetErrorStream().PutCString(
- "error: the lua script interpreter is not yet implemented.\n");
- return false;
+ CommandReturnObject *result,
+ const ExecuteScriptOptions &options) {
+ Lua l;
+ if (llvm::Error e = l.Run(command)) {
+ result->AppendErrorWithFormatv(
+ "lua failed attempting to evaluate '{0}': {1}\n", command,
+ llvm::toString(std::move(e)));
+ return false;
+ }
+ return true;
}
void ScriptInterpreterLua::ExecuteInterpreterLoop() {
- m_debugger.GetErrorStream().PutCString(
- "error: the lua script interpreter is not yet implemented.\n");
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
+
+ Debugger &debugger = m_debugger;
+
+ // At the moment, the only time the debugger does not have an input file
+ // handle is when this is called directly from lua, in which case it is
+ // both dangerous and unnecessary (not to mention confusing) to try to embed
+ // a running interpreter loop inside the already running lua interpreter
+ // loop, so we won't do it.
+
+ if (!debugger.GetInputFile().IsValid())
+ return;
+
+ IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(debugger));
+ debugger.PushIOHandler(io_handler_sp);
}
void ScriptInterpreterLua::Initialize() {
diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt
index d2fda3c45b31..b22ef6b79d50 100644
--- a/lldb/test/CMakeLists.txt
+++ b/lldb/test/CMakeLists.txt
@@ -144,6 +144,7 @@ endif()
# These values are not canonicalized within LLVM.
llvm_canonicalize_cmake_booleans(
LLDB_ENABLE_PYTHON
+ LLDB_ENABLE_LUA
LLVM_ENABLE_ZLIB
LLVM_ENABLE_SHARED_LIBS
LLDB_IS_64_BITS)
diff --git a/lldb/test/Shell/ScriptInterpreter/Lua/lua.test b/lldb/test/Shell/ScriptInterpreter/Lua/lua.test
new file mode 100644
index 000000000000..70184edbab1a
--- /dev/null
+++ b/lldb/test/Shell/ScriptInterpreter/Lua/lua.test
@@ -0,0 +1,3 @@
+# REQUIRES: lua
+# RUN: %lldb --script-language lua -o 'script print(1000+100+10+1)' 2>&1 | FileCheck %s
+# CHECK: 1111
diff --git a/lldb/test/Shell/lit.cfg.py b/lldb/test/Shell/lit.cfg.py
index c0a60914551d..cc6155f05cd2 100644
--- a/lldb/test/Shell/lit.cfg.py
+++ b/lldb/test/Shell/lit.cfg.py
@@ -103,6 +103,9 @@ def calculate_arch_features(arch_string):
if config.lldb_enable_python:
config.available_features.add('python')
+if config.lldb_enable_lua:
+ config.available_features.add('lua')
+
if config.lldb_enable_lzma:
config.available_features.add('lzma')
diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in
index b391f8ba31e6..d998a0ca51c9 100644
--- a/lldb/test/Shell/lit.site.cfg.py.in
+++ b/lldb/test/Shell/lit.site.cfg.py.in
@@ -19,6 +19,7 @@ config.lldb_enable_lzma = @LLDB_ENABLE_LZMA@
config.host_triple = "@LLVM_HOST_TRIPLE@"
config.lldb_bitness = 64 if @LLDB_IS_64_BITS@ else 32
config.lldb_enable_python = @LLDB_ENABLE_PYTHON@
+config.lldb_enable_lua = @LLDB_ENABLE_LUA@
config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@"
# The shell tests use their own module caches.
config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-shell")
diff --git a/lldb/unittests/ScriptInterpreter/CMakeLists.txt b/lldb/unittests/ScriptInterpreter/CMakeLists.txt
index 06d909b862a0..82cd128a6138 100644
--- a/lldb/unittests/ScriptInterpreter/CMakeLists.txt
+++ b/lldb/unittests/ScriptInterpreter/CMakeLists.txt
@@ -1,3 +1,6 @@
if (LLDB_ENABLE_PYTHON)
add_subdirectory(Python)
endif()
+if (LLDB_ENABLE_LUA)
+ add_subdirectory(Lua)
+endif()
diff --git a/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt b/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
new file mode 100644
index 000000000000..aa8a95c7c54c
--- /dev/null
+++ b/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_unittest(ScriptInterpreterLuaTests
+ LuaTests.cpp
+ ScriptInterpreterTests.cpp
+
+ LINK_LIBS
+ lldbHost
+ lldbPluginScriptInterpreterLua
+ lldbPluginPlatformLinux
+ LLVMTestingSupport
+ LINK_COMPONENTS
+ Support
+ )
\ No newline at end of file
diff --git a/lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp b/lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp
new file mode 100644
index 000000000000..fa8e61a69b3f
--- /dev/null
+++ b/lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp
@@ -0,0 +1,26 @@
+//===-- LuaTests.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ScriptInterpreter/Lua/Lua.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+
+TEST(LuaTest, RunValid) {
+ Lua lua;
+ llvm::Error error = lua.Run("foo = 1");
+ EXPECT_FALSE(static_cast<bool>(error));
+}
+
+TEST(LuaTest, RunInvalid) {
+ Lua lua;
+ llvm::Error error = lua.Run("nil = foo");
+ EXPECT_TRUE(static_cast<bool>(error));
+ EXPECT_EQ(llvm::toString(std::move(error)),
+ "[string \"buffer\"]:1: unexpected symbol near 'nil'\n");
+}
diff --git a/lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp b/lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp
new file mode 100644
index 000000000000..b5324f6ba9a5
--- /dev/null
+++ b/lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp
@@ -0,0 +1,62 @@
+//===-- LuaTests.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Utility/Reproducer.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb_private::repro;
+using namespace lldb;
+
+namespace {
+class ScriptInterpreterTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ llvm::cantFail(Reproducer::Initialize(ReproducerMode::Off, llvm::None));
+ FileSystem::Initialize();
+ HostInfo::Initialize();
+
+ // Pretend Linux is the host platform.
+ platform_linux::PlatformLinux::Initialize();
+ ArchSpec arch("powerpc64-pc-linux");
+ Platform::SetHostPlatform(
+ platform_linux::PlatformLinux::CreateInstance(true, &arch));
+ }
+ void TearDown() override {
+ platform_linux::PlatformLinux::Terminate();
+ HostInfo::Terminate();
+ FileSystem::Terminate();
+ Reproducer::Terminate();
+ }
+};
+} // namespace
+
+TEST_F(ScriptInterpreterTest, Plugin) {
+ EXPECT_EQ(ScriptInterpreterLua::GetPluginNameStatic(), "script-lua");
+ EXPECT_EQ(ScriptInterpreterLua::GetPluginDescriptionStatic(),
+ "Lua script interpreter");
+}
+
+TEST_F(ScriptInterpreterTest, ExecuteOneLine) {
+ DebuggerSP debugger_sp = Debugger::CreateInstance();
+ ASSERT_TRUE(debugger_sp);
+
+ ScriptInterpreterLua script_interpreter(*debugger_sp);
+ CommandReturnObject result;
+ EXPECT_TRUE(script_interpreter.ExecuteOneLine("foo = 1", &result));
+ EXPECT_FALSE(script_interpreter.ExecuteOneLine("nil = foo", &result));
+ EXPECT_TRUE(result.GetErrorData().startswith(
+ "error: lua failed attempting to evaluate 'nil = foo'"));
+}
More information about the lldb-commits
mailing list