15ffd83dbSDimitry Andric //===-- ScriptInterpreterLua.cpp ------------------------------------------===// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric 9480093f4SDimitry Andric #include "ScriptInterpreterLua.h" 10480093f4SDimitry Andric #include "Lua.h" 11*e8d8bef9SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h" 12480093f4SDimitry Andric #include "lldb/Core/Debugger.h" 13480093f4SDimitry Andric #include "lldb/Core/PluginManager.h" 14480093f4SDimitry Andric #include "lldb/Core/StreamFile.h" 15480093f4SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 16*e8d8bef9SDimitry Andric #include "lldb/Target/ExecutionContext.h" 17480093f4SDimitry Andric #include "lldb/Utility/Stream.h" 18480093f4SDimitry Andric #include "lldb/Utility/StringList.h" 19480093f4SDimitry Andric #include "lldb/Utility/Timer.h" 20*e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h" 215ffd83dbSDimitry Andric #include "llvm/Support/FormatAdapters.h" 22*e8d8bef9SDimitry Andric #include <memory> 23*e8d8bef9SDimitry Andric #include <vector> 24480093f4SDimitry Andric 25480093f4SDimitry Andric using namespace lldb; 26480093f4SDimitry Andric using namespace lldb_private; 27480093f4SDimitry Andric 285ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) 295ffd83dbSDimitry Andric 30*e8d8bef9SDimitry Andric enum ActiveIOHandler { 31*e8d8bef9SDimitry Andric eIOHandlerNone, 32*e8d8bef9SDimitry Andric eIOHandlerBreakpoint, 33*e8d8bef9SDimitry Andric eIOHandlerWatchpoint 34*e8d8bef9SDimitry Andric }; 35*e8d8bef9SDimitry Andric 36480093f4SDimitry Andric class IOHandlerLuaInterpreter : public IOHandlerDelegate, 37480093f4SDimitry Andric public IOHandlerEditline { 38480093f4SDimitry Andric public: 39480093f4SDimitry Andric IOHandlerLuaInterpreter(Debugger &debugger, 40*e8d8bef9SDimitry Andric ScriptInterpreterLua &script_interpreter, 41*e8d8bef9SDimitry Andric ActiveIOHandler active_io_handler = eIOHandlerNone) 42480093f4SDimitry Andric : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", 43480093f4SDimitry Andric ">>> ", "..> ", true, debugger.GetUseColor(), 0, 44480093f4SDimitry Andric *this, nullptr), 45*e8d8bef9SDimitry Andric m_script_interpreter(script_interpreter), 46*e8d8bef9SDimitry Andric m_active_io_handler(active_io_handler) { 475ffd83dbSDimitry Andric llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( 485ffd83dbSDimitry Andric debugger.GetOutputFile().GetStream(), 495ffd83dbSDimitry Andric debugger.GetErrorFile().GetStream())); 50480093f4SDimitry Andric llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); 51480093f4SDimitry Andric } 52480093f4SDimitry Andric 535ffd83dbSDimitry Andric ~IOHandlerLuaInterpreter() override { 54480093f4SDimitry Andric llvm::cantFail(m_script_interpreter.LeaveSession()); 55480093f4SDimitry Andric } 56480093f4SDimitry Andric 57*e8d8bef9SDimitry Andric void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 58*e8d8bef9SDimitry Andric const char *instructions = nullptr; 59*e8d8bef9SDimitry Andric switch (m_active_io_handler) { 60*e8d8bef9SDimitry Andric case eIOHandlerNone: 61*e8d8bef9SDimitry Andric case eIOHandlerWatchpoint: 62*e8d8bef9SDimitry Andric break; 63*e8d8bef9SDimitry Andric case eIOHandlerBreakpoint: 64*e8d8bef9SDimitry Andric instructions = "Enter your Lua command(s). Type 'quit' to end.\n" 65*e8d8bef9SDimitry Andric "The commands are compiled as the body of the following " 66*e8d8bef9SDimitry Andric "Lua function\n" 67*e8d8bef9SDimitry Andric "function (frame, bp_loc, ...) end\n"; 68*e8d8bef9SDimitry Andric SetPrompt(llvm::StringRef("..> ")); 69*e8d8bef9SDimitry Andric break; 70*e8d8bef9SDimitry Andric } 71*e8d8bef9SDimitry Andric if (instructions == nullptr) 72*e8d8bef9SDimitry Andric return; 73*e8d8bef9SDimitry Andric if (interactive) 74*e8d8bef9SDimitry Andric *io_handler.GetOutputStreamFileSP() << instructions; 75*e8d8bef9SDimitry Andric } 76*e8d8bef9SDimitry Andric 77*e8d8bef9SDimitry Andric bool IOHandlerIsInputComplete(IOHandler &io_handler, 78*e8d8bef9SDimitry Andric StringList &lines) override { 79*e8d8bef9SDimitry Andric size_t last = lines.GetSize() - 1; 80*e8d8bef9SDimitry Andric if (IsQuitCommand(lines.GetStringAtIndex(last))) { 81*e8d8bef9SDimitry Andric if (m_active_io_handler == eIOHandlerBreakpoint) 82*e8d8bef9SDimitry Andric lines.DeleteStringAtIndex(last); 83*e8d8bef9SDimitry Andric return true; 84*e8d8bef9SDimitry Andric } 85*e8d8bef9SDimitry Andric StreamString str; 86*e8d8bef9SDimitry Andric lines.Join("\n", str); 87*e8d8bef9SDimitry Andric if (llvm::Error E = 88*e8d8bef9SDimitry Andric m_script_interpreter.GetLua().CheckSyntax(str.GetString())) { 89*e8d8bef9SDimitry Andric std::string error_str = toString(std::move(E)); 90*e8d8bef9SDimitry Andric // Lua always errors out to incomplete code with '<eof>' 91*e8d8bef9SDimitry Andric return error_str.find("<eof>") == std::string::npos; 92*e8d8bef9SDimitry Andric } 93*e8d8bef9SDimitry Andric // The breakpoint handler only exits with a explicit 'quit' 94*e8d8bef9SDimitry Andric return m_active_io_handler != eIOHandlerBreakpoint; 95*e8d8bef9SDimitry Andric } 96*e8d8bef9SDimitry Andric 97480093f4SDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler, 98480093f4SDimitry Andric std::string &data) override { 99*e8d8bef9SDimitry Andric switch (m_active_io_handler) { 100*e8d8bef9SDimitry Andric case eIOHandlerBreakpoint: { 101*e8d8bef9SDimitry Andric auto *bp_options_vec = static_cast<std::vector<BreakpointOptions *> *>( 102*e8d8bef9SDimitry Andric io_handler.GetUserData()); 103*e8d8bef9SDimitry Andric for (auto *bp_options : *bp_options_vec) { 104*e8d8bef9SDimitry Andric Status error = m_script_interpreter.SetBreakpointCommandCallback( 105*e8d8bef9SDimitry Andric bp_options, data.c_str()); 106*e8d8bef9SDimitry Andric if (error.Fail()) 107*e8d8bef9SDimitry Andric *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n'; 108*e8d8bef9SDimitry Andric } 109*e8d8bef9SDimitry Andric io_handler.SetIsDone(true); 110*e8d8bef9SDimitry Andric } break; 111*e8d8bef9SDimitry Andric case eIOHandlerWatchpoint: 112*e8d8bef9SDimitry Andric io_handler.SetIsDone(true); 113*e8d8bef9SDimitry Andric break; 114*e8d8bef9SDimitry Andric case eIOHandlerNone: 115*e8d8bef9SDimitry Andric if (IsQuitCommand(data)) { 1165ffd83dbSDimitry Andric io_handler.SetIsDone(true); 1175ffd83dbSDimitry Andric return; 1185ffd83dbSDimitry Andric } 119*e8d8bef9SDimitry Andric if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) 120*e8d8bef9SDimitry Andric *io_handler.GetErrorStreamFileSP() << toString(std::move(error)); 121*e8d8bef9SDimitry Andric break; 122480093f4SDimitry Andric } 123480093f4SDimitry Andric } 124480093f4SDimitry Andric 125480093f4SDimitry Andric private: 126480093f4SDimitry Andric ScriptInterpreterLua &m_script_interpreter; 127*e8d8bef9SDimitry Andric ActiveIOHandler m_active_io_handler; 128*e8d8bef9SDimitry Andric 129*e8d8bef9SDimitry Andric bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; } 130480093f4SDimitry Andric }; 131480093f4SDimitry Andric 132480093f4SDimitry Andric ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) 133480093f4SDimitry Andric : ScriptInterpreter(debugger, eScriptLanguageLua), 134480093f4SDimitry Andric m_lua(std::make_unique<Lua>()) {} 135480093f4SDimitry Andric 136480093f4SDimitry Andric ScriptInterpreterLua::~ScriptInterpreterLua() {} 137480093f4SDimitry Andric 138480093f4SDimitry Andric bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, 139480093f4SDimitry Andric CommandReturnObject *result, 140480093f4SDimitry Andric const ExecuteScriptOptions &options) { 1415ffd83dbSDimitry Andric if (command.empty()) { 1425ffd83dbSDimitry Andric if (result) 1435ffd83dbSDimitry Andric result->AppendError("empty command passed to lua\n"); 1445ffd83dbSDimitry Andric return false; 1455ffd83dbSDimitry Andric } 1465ffd83dbSDimitry Andric 1475ffd83dbSDimitry Andric llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 1485ffd83dbSDimitry Andric io_redirect_or_error = ScriptInterpreterIORedirect::Create( 1495ffd83dbSDimitry Andric options.GetEnableIO(), m_debugger, result); 1505ffd83dbSDimitry Andric if (!io_redirect_or_error) { 1515ffd83dbSDimitry Andric if (result) 1525ffd83dbSDimitry Andric result->AppendErrorWithFormatv( 1535ffd83dbSDimitry Andric "failed to redirect I/O: {0}\n", 1545ffd83dbSDimitry Andric llvm::fmt_consume(io_redirect_or_error.takeError())); 1555ffd83dbSDimitry Andric else 1565ffd83dbSDimitry Andric llvm::consumeError(io_redirect_or_error.takeError()); 1575ffd83dbSDimitry Andric return false; 1585ffd83dbSDimitry Andric } 1595ffd83dbSDimitry Andric 1605ffd83dbSDimitry Andric ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; 1615ffd83dbSDimitry Andric 1625ffd83dbSDimitry Andric if (llvm::Error e = 1635ffd83dbSDimitry Andric m_lua->ChangeIO(io_redirect.GetOutputFile()->GetStream(), 1645ffd83dbSDimitry Andric io_redirect.GetErrorFile()->GetStream())) { 1655ffd83dbSDimitry Andric result->AppendErrorWithFormatv("lua failed to redirect I/O: {0}\n", 1665ffd83dbSDimitry Andric llvm::toString(std::move(e))); 1675ffd83dbSDimitry Andric return false; 1685ffd83dbSDimitry Andric } 1695ffd83dbSDimitry Andric 170480093f4SDimitry Andric if (llvm::Error e = m_lua->Run(command)) { 171480093f4SDimitry Andric result->AppendErrorWithFormatv( 172480093f4SDimitry Andric "lua failed attempting to evaluate '{0}': {1}\n", command, 173480093f4SDimitry Andric llvm::toString(std::move(e))); 174480093f4SDimitry Andric return false; 175480093f4SDimitry Andric } 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric io_redirect.Flush(); 178480093f4SDimitry Andric return true; 179480093f4SDimitry Andric } 180480093f4SDimitry Andric 181480093f4SDimitry Andric void ScriptInterpreterLua::ExecuteInterpreterLoop() { 182*e8d8bef9SDimitry Andric LLDB_SCOPED_TIMER(); 183480093f4SDimitry Andric 184480093f4SDimitry Andric // At the moment, the only time the debugger does not have an input file 185480093f4SDimitry Andric // handle is when this is called directly from lua, in which case it is 186480093f4SDimitry Andric // both dangerous and unnecessary (not to mention confusing) to try to embed 187480093f4SDimitry Andric // a running interpreter loop inside the already running lua interpreter 188480093f4SDimitry Andric // loop, so we won't do it. 1895ffd83dbSDimitry Andric if (!m_debugger.GetInputFile().IsValid()) 190480093f4SDimitry Andric return; 191480093f4SDimitry Andric 1925ffd83dbSDimitry Andric IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(m_debugger, *this)); 1935ffd83dbSDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 194480093f4SDimitry Andric } 195480093f4SDimitry Andric 196480093f4SDimitry Andric bool ScriptInterpreterLua::LoadScriptingModule( 197480093f4SDimitry Andric const char *filename, bool init_session, lldb_private::Status &error, 198*e8d8bef9SDimitry Andric StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) { 199480093f4SDimitry Andric 2005ffd83dbSDimitry Andric FileSystem::Instance().Collect(filename); 201480093f4SDimitry Andric if (llvm::Error e = m_lua->LoadModule(filename)) { 202480093f4SDimitry Andric error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n", 203480093f4SDimitry Andric filename, llvm::toString(std::move(e))); 204480093f4SDimitry Andric return false; 205480093f4SDimitry Andric } 206480093f4SDimitry Andric return true; 207480093f4SDimitry Andric } 208480093f4SDimitry Andric 209480093f4SDimitry Andric void ScriptInterpreterLua::Initialize() { 210480093f4SDimitry Andric static llvm::once_flag g_once_flag; 211480093f4SDimitry Andric 212480093f4SDimitry Andric llvm::call_once(g_once_flag, []() { 213480093f4SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 214480093f4SDimitry Andric GetPluginDescriptionStatic(), 215480093f4SDimitry Andric lldb::eScriptLanguageLua, CreateInstance); 216480093f4SDimitry Andric }); 217480093f4SDimitry Andric } 218480093f4SDimitry Andric 219480093f4SDimitry Andric void ScriptInterpreterLua::Terminate() {} 220480093f4SDimitry Andric 221480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) { 222480093f4SDimitry Andric if (m_session_is_active) 223480093f4SDimitry Andric return llvm::Error::success(); 224480093f4SDimitry Andric 225480093f4SDimitry Andric const char *fmt_str = 226480093f4SDimitry Andric "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); " 227480093f4SDimitry Andric "lldb.target = lldb.debugger:GetSelectedTarget(); " 228480093f4SDimitry Andric "lldb.process = lldb.target:GetProcess(); " 229480093f4SDimitry Andric "lldb.thread = lldb.process:GetSelectedThread(); " 230480093f4SDimitry Andric "lldb.frame = lldb.thread:GetSelectedFrame()"; 231480093f4SDimitry Andric return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str()); 232480093f4SDimitry Andric } 233480093f4SDimitry Andric 234480093f4SDimitry Andric llvm::Error ScriptInterpreterLua::LeaveSession() { 235480093f4SDimitry Andric if (!m_session_is_active) 236480093f4SDimitry Andric return llvm::Error::success(); 237480093f4SDimitry Andric 238480093f4SDimitry Andric m_session_is_active = false; 239480093f4SDimitry Andric 240480093f4SDimitry Andric llvm::StringRef str = "lldb.debugger = nil; " 241480093f4SDimitry Andric "lldb.target = nil; " 242480093f4SDimitry Andric "lldb.process = nil; " 243480093f4SDimitry Andric "lldb.thread = nil; " 244480093f4SDimitry Andric "lldb.frame = nil"; 245480093f4SDimitry Andric return m_lua->Run(str); 246480093f4SDimitry Andric } 247480093f4SDimitry Andric 248*e8d8bef9SDimitry Andric bool ScriptInterpreterLua::BreakpointCallbackFunction( 249*e8d8bef9SDimitry Andric void *baton, StoppointCallbackContext *context, user_id_t break_id, 250*e8d8bef9SDimitry Andric user_id_t break_loc_id) { 251*e8d8bef9SDimitry Andric assert(context); 252*e8d8bef9SDimitry Andric 253*e8d8bef9SDimitry Andric ExecutionContext exe_ctx(context->exe_ctx_ref); 254*e8d8bef9SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 255*e8d8bef9SDimitry Andric if (target == nullptr) 256*e8d8bef9SDimitry Andric return true; 257*e8d8bef9SDimitry Andric 258*e8d8bef9SDimitry Andric StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); 259*e8d8bef9SDimitry Andric BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); 260*e8d8bef9SDimitry Andric BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id)); 261*e8d8bef9SDimitry Andric 262*e8d8bef9SDimitry Andric Debugger &debugger = target->GetDebugger(); 263*e8d8bef9SDimitry Andric ScriptInterpreterLua *lua_interpreter = static_cast<ScriptInterpreterLua *>( 264*e8d8bef9SDimitry Andric debugger.GetScriptInterpreter(true, eScriptLanguageLua)); 265*e8d8bef9SDimitry Andric Lua &lua = lua_interpreter->GetLua(); 266*e8d8bef9SDimitry Andric 267*e8d8bef9SDimitry Andric CommandDataLua *bp_option_data = static_cast<CommandDataLua *>(baton); 268*e8d8bef9SDimitry Andric llvm::Expected<bool> BoolOrErr = lua.CallBreakpointCallback( 269*e8d8bef9SDimitry Andric baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp); 270*e8d8bef9SDimitry Andric if (llvm::Error E = BoolOrErr.takeError()) { 271*e8d8bef9SDimitry Andric debugger.GetErrorStream() << toString(std::move(E)); 272*e8d8bef9SDimitry Andric return true; 273*e8d8bef9SDimitry Andric } 274*e8d8bef9SDimitry Andric 275*e8d8bef9SDimitry Andric return *BoolOrErr; 276*e8d8bef9SDimitry Andric } 277*e8d8bef9SDimitry Andric 278*e8d8bef9SDimitry Andric void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback( 279*e8d8bef9SDimitry Andric std::vector<BreakpointOptions *> &bp_options_vec, 280*e8d8bef9SDimitry Andric CommandReturnObject &result) { 281*e8d8bef9SDimitry Andric IOHandlerSP io_handler_sp( 282*e8d8bef9SDimitry Andric new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint)); 283*e8d8bef9SDimitry Andric io_handler_sp->SetUserData(&bp_options_vec); 284*e8d8bef9SDimitry Andric m_debugger.RunIOHandlerAsync(io_handler_sp); 285*e8d8bef9SDimitry Andric } 286*e8d8bef9SDimitry Andric 287*e8d8bef9SDimitry Andric Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction( 288*e8d8bef9SDimitry Andric BreakpointOptions *bp_options, const char *function_name, 289*e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 290*e8d8bef9SDimitry Andric const char *fmt_str = "return {0}(frame, bp_loc, ...)"; 291*e8d8bef9SDimitry Andric std::string oneliner = llvm::formatv(fmt_str, function_name).str(); 292*e8d8bef9SDimitry Andric return RegisterBreakpointCallback(bp_options, oneliner.c_str(), 293*e8d8bef9SDimitry Andric extra_args_sp); 294*e8d8bef9SDimitry Andric } 295*e8d8bef9SDimitry Andric 296*e8d8bef9SDimitry Andric Status ScriptInterpreterLua::SetBreakpointCommandCallback( 297*e8d8bef9SDimitry Andric BreakpointOptions *bp_options, const char *command_body_text) { 298*e8d8bef9SDimitry Andric return RegisterBreakpointCallback(bp_options, command_body_text, {}); 299*e8d8bef9SDimitry Andric } 300*e8d8bef9SDimitry Andric 301*e8d8bef9SDimitry Andric Status ScriptInterpreterLua::RegisterBreakpointCallback( 302*e8d8bef9SDimitry Andric BreakpointOptions *bp_options, const char *command_body_text, 303*e8d8bef9SDimitry Andric StructuredData::ObjectSP extra_args_sp) { 304*e8d8bef9SDimitry Andric Status error; 305*e8d8bef9SDimitry Andric auto data_up = std::make_unique<CommandDataLua>(extra_args_sp); 306*e8d8bef9SDimitry Andric error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text); 307*e8d8bef9SDimitry Andric if (error.Fail()) 308*e8d8bef9SDimitry Andric return error; 309*e8d8bef9SDimitry Andric auto baton_sp = 310*e8d8bef9SDimitry Andric std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up)); 311*e8d8bef9SDimitry Andric bp_options->SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction, 312*e8d8bef9SDimitry Andric baton_sp); 313*e8d8bef9SDimitry Andric return error; 314*e8d8bef9SDimitry Andric } 315*e8d8bef9SDimitry Andric 316480093f4SDimitry Andric lldb::ScriptInterpreterSP 317480093f4SDimitry Andric ScriptInterpreterLua::CreateInstance(Debugger &debugger) { 318480093f4SDimitry Andric return std::make_shared<ScriptInterpreterLua>(debugger); 319480093f4SDimitry Andric } 320480093f4SDimitry Andric 321480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginNameStatic() { 322480093f4SDimitry Andric static ConstString g_name("script-lua"); 323480093f4SDimitry Andric return g_name; 324480093f4SDimitry Andric } 325480093f4SDimitry Andric 326480093f4SDimitry Andric const char *ScriptInterpreterLua::GetPluginDescriptionStatic() { 327480093f4SDimitry Andric return "Lua script interpreter"; 328480093f4SDimitry Andric } 329480093f4SDimitry Andric 330480093f4SDimitry Andric lldb_private::ConstString ScriptInterpreterLua::GetPluginName() { 331480093f4SDimitry Andric return GetPluginNameStatic(); 332480093f4SDimitry Andric } 333480093f4SDimitry Andric 334480093f4SDimitry Andric uint32_t ScriptInterpreterLua::GetPluginVersion() { return 1; } 335480093f4SDimitry Andric 336480093f4SDimitry Andric Lua &ScriptInterpreterLua::GetLua() { return *m_lua; } 337