1 //===-- Lua.cpp -----------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Lua.h"
10 #include "lldb/Host/FileSystem.h"
11 #include "lldb/Utility/FileSpec.h"
12 #include "llvm/Support/FormatVariadic.h"
13 
14 using namespace lldb_private;
15 using namespace lldb;
16 
17 llvm::Error Lua::Run(llvm::StringRef buffer) {
18   int error =
19       luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") ||
20       lua_pcall(m_lua_state, 0, 0, 0);
21   if (!error)
22     return llvm::Error::success();
23 
24   llvm::Error e = llvm::make_error<llvm::StringError>(
25       llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
26       llvm::inconvertibleErrorCode());
27   // Pop error message from the stack.
28   lua_pop(m_lua_state, 1);
29   return e;
30 }
31 
32 llvm::Error Lua::LoadModule(llvm::StringRef filename) {
33   FileSpec file(filename);
34   if (!FileSystem::Instance().Exists(file)) {
35     return llvm::make_error<llvm::StringError>("invalid path",
36                                                llvm::inconvertibleErrorCode());
37   }
38 
39   ConstString module_extension = file.GetFileNameExtension();
40   if (module_extension != ".lua") {
41     return llvm::make_error<llvm::StringError>("invalid extension",
42                                                llvm::inconvertibleErrorCode());
43   }
44 
45   int error = luaL_loadfile(m_lua_state, filename.data()) ||
46               lua_pcall(m_lua_state, 0, 1, 0);
47   if (error) {
48     llvm::Error e = llvm::make_error<llvm::StringError>(
49         llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)),
50         llvm::inconvertibleErrorCode());
51     // Pop error message from the stack.
52     lua_pop(m_lua_state, 1);
53     return e;
54   }
55 
56   ConstString module_name = file.GetFileNameStrippingExtension();
57   lua_setglobal(m_lua_state, module_name.GetCString());
58   return llvm::Error::success();
59 }
60 
61 llvm::Error Lua::ChangeIO(FILE *out, FILE *err) {
62   assert(out != nullptr);
63   assert(err != nullptr);
64 
65   lua_getglobal(m_lua_state, "io");
66 
67   lua_getfield(m_lua_state, -1, "stdout");
68   if (luaL_Stream *s = static_cast<luaL_Stream *>(
69           luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
70     s->f = out;
71     lua_pop(m_lua_state, 1);
72   } else {
73     lua_pop(m_lua_state, 2);
74     return llvm::make_error<llvm::StringError>("could not get stdout",
75                                                llvm::inconvertibleErrorCode());
76   }
77 
78   lua_getfield(m_lua_state, -1, "stderr");
79   if (luaL_Stream *s = static_cast<luaL_Stream *>(
80           luaL_testudata(m_lua_state, -1, LUA_FILEHANDLE))) {
81     s->f = out;
82     lua_pop(m_lua_state, 1);
83   } else {
84     lua_pop(m_lua_state, 2);
85     return llvm::make_error<llvm::StringError>("could not get stderr",
86                                                llvm::inconvertibleErrorCode());
87   }
88 
89   lua_pop(m_lua_state, 1);
90   return llvm::Error::success();
91 }
92