using System.Linq; using System.Reflection; using System.Text; using System.Threading; using Discord.Commands; using NLua; namespace ChaosBot.Services.ProgrammingLanguageInterpreter { internal class LuaProgrammingLanguageInterpreter : IProgrammingLanguageInterpreter { private readonly StringBuilder _outputBuilder = new StringBuilder(); private CancellationToken _ct; private Lua _state; public string Interpret(CancellationToken ct, SocketCommandContext context, string content, string command) { LoggingFacade.Debug($"Interpreting code for {command} using Lua"); LoggingFacade.Trace($"Using CancellationToken: {ct}"); _ct = ct; LoggingFacade.Trace("Starting Lua interpreter"); _state = new Lua(); LoggingFacade.Trace("Setting Lua debug hook"); _state.SetDebugHook(KeraLua.LuaHookMask.Line, 0); _state.DebugHook += LuaDebugHook; MethodInfo printMethod = GetType().GetMethod("Print", BindingFlags.NonPublic | BindingFlags.Instance); LoggingFacade.Info($"Overwriting print function with {printMethod}"); _state["print"] = printMethod; LoggingFacade.Trace("Disabling Lua `import` function"); _state.DoString ("\nimport = function () end\n"); LoggingFacade.Trace("Running user Lua code"); _state.DoString(content, command); LoggingFacade.Trace("Returning Lua output"); return _outputBuilder.ToString(); } private void LuaDebugHook(object sender, NLua.Event.DebugHookEventArgs e) { if (_ct.IsCancellationRequested) { Lua l = (Lua) sender; l.State.Error("Timeout kill"); } } // This is being used in the `Interpret` function to register the print function // ReSharper disable once UnusedMember.Local private void Print(params object[] parameters) { string str = string.Join(" ", from param in parameters select param == null ? string.Empty : param.ToString()); _outputBuilder.Append(str); } } }