JDevlieghere updated this revision to Diff 233877.
JDevlieghere added a comment.

- Rebase
- Hide C calls behind C++ abstraction
- Improve error handling
- Add unit test


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D71234/new/

https://reviews.llvm.org/D71234

Files:
  lldb/include/lldb/Core/IOHandler.h
  lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
  lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
  lldb/unittests/ScriptInterpreter/CMakeLists.txt
  lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
  lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp

Index: lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/ScriptInterpreter/Lua/LuaTests.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'"));
+}
Index: lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_unittest(ScriptInterpreterLuaTests
+  LuaTests.cpp
+
+  LINK_LIBS
+    lldbHost
+    lldbPluginScriptInterpreterLua
+    lldbPluginPlatformLinux
+    LLVMTestingSupport
+  LINK_COMPONENTS
+    Support
+  )
\ No newline at end of file
Index: lldb/unittests/ScriptInterpreter/CMakeLists.txt
===================================================================
--- lldb/unittests/ScriptInterpreter/CMakeLists.txt
+++ 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()
Index: lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp
@@ -10,32 +10,114 @@
 #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 "lldb/Utility/Timer.h"
 #include "llvm/Support/Threading.h"
 
+#ifndef LLDB_DISABLE_LIBEDIT
+#include "lldb/Host/Editline.h"
+#endif
+
+#include "lua.hpp"
+
+#define LUA_PROMPT ">>> "
+
 #include <mutex>
 
 using namespace lldb;
 using 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) {
+    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;
+  }
+
+private:
+  lua_State *m_lua_state = nullptr;
+};
+
+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)) {
+      fprintf(GetOutputFILE(), "%s", llvm::toString(std::move(error)).c_str());
+    }
+  }
+
+  ~IOHandlerLuaInterpreter() override {}
+
+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));
+  if (io_handler_sp) {
+    debugger.PushIOHandler(io_handler_sp);
+  }
 }
 
 void ScriptInterpreterLua::Initialize() {
Index: lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
+++ lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
@@ -4,4 +4,8 @@
   LINK_LIBS
     lldbCore
     lldbInterpreter
-  )
\ No newline at end of file
+  )
+
+find_package(Lua REQUIRED)
+target_include_directories(lldbPluginScriptInterpreterLua PRIVATE ${LUA_INCLUDE_DIR})
+target_link_libraries(lldbPluginScriptInterpreterLua PRIVATE ${LUA_LIBRARIES})
Index: lldb/include/lldb/Core/IOHandler.h
===================================================================
--- lldb/include/lldb/Core/IOHandler.h
+++ lldb/include/lldb/Core/IOHandler.h
@@ -52,6 +52,7 @@
     REPL,
     ProcessIO,
     PythonInterpreter,
+    LuaInterpreter,
     PythonCode,
     Other
   };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to