MainForm.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Diagnostics;
  6. using System.Drawing;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Windows.Forms;
  12. using MoonSharp.Interpreter;
  13. using MoonSharp.Interpreter.CoreLib;
  14. using MoonSharp.Interpreter.Debugging;
  15. using MoonSharp.Interpreter.Execution;
  16. using MoonSharp.Interpreter.Execution.VM;
  17. using MoonSharp.Interpreter.Loaders;
  18. namespace MoonSharp.Debugger
  19. {
  20. public partial class MainForm : Form, IDebugger
  21. {
  22. List<string> m_Watches = new List<string>();
  23. public MainForm()
  24. {
  25. InitializeComponent();
  26. }
  27. private void MainForm_Load(object sender, EventArgs e)
  28. {
  29. m_Ctx = SynchronizationContext.Current;
  30. MoonSharpInterpreter.WarmUp();
  31. }
  32. private void openToolStripMenuItem_Click(object sender, EventArgs e)
  33. {
  34. OpenFileDialog ofd = new OpenFileDialog();
  35. ofd.Title = "Load script";
  36. ofd.DefaultExt = "lua";
  37. ofd.Filter = "Lua files (*.lua)|*.lua|All files (*.*)|*.*";
  38. if (ofd.ShowDialog() == DialogResult.OK)
  39. {
  40. DebugScript(ofd.FileName);
  41. openToolStripMenuItem.Enabled = false;
  42. }
  43. }
  44. Script m_Script;
  45. SynchronizationContext m_Ctx;
  46. DynValue Assert(ScriptExecutionContext executionContext, CallbackArguments values)
  47. {
  48. if (!values[0].CastToBool())
  49. Console_WriteLine("ASSERT FAILED!");
  50. return DynValue.Nil;
  51. }
  52. DynValue XAssert(ScriptExecutionContext executionContext, CallbackArguments values)
  53. {
  54. if (!values[1].CastToBool())
  55. Console_WriteLine("ASSERT FAILED! : {0}", values[0].ToString());
  56. return DynValue.Nil;
  57. }
  58. private void Console_WriteLine(string fmt, params object[] args)
  59. {
  60. fmt = string.Format(fmt, args);
  61. m_Ctx.Post(str =>
  62. {
  63. txtOutput.Text = txtOutput.Text + fmt.ToString() + "\n";
  64. txtOutput.SelectionStart = txtOutput.Text.Length - 1;
  65. txtOutput.SelectionLength = 0;
  66. txtOutput.ScrollToCaret();
  67. }, fmt);
  68. }
  69. private void DebugScript(string filename)
  70. {
  71. m_Script = new Script(CoreModules.Preset_Complete);
  72. m_Script.DebugPrint = s => { Console_WriteLine("{0}", s); };
  73. //m_Script.Globals["assert"] = DynValue.NewCallback(Assert);
  74. m_Script.Globals.Set("xassert", DynValue.NewCallback(XAssert));
  75. var L = new ClassicLuaScriptLoader();
  76. L.ModulePaths = L.UnpackStringPaths("Modules/?;Modules/?.lua");
  77. m_Script.ScriptLoader = L;
  78. m_Script.LoadFile(filename);
  79. m_Script.AttachDebugger(this);
  80. Thread m_Debugger = new Thread(DebugMain);
  81. m_Debugger.Name = "Moon# Execution Thread";
  82. m_Debugger.IsBackground = true;
  83. m_Debugger.Start();
  84. }
  85. void IDebugger.SetSourceCode(ByteCode byteCode, string[] code)
  86. {
  87. string[] source = new string[byteCode.Code.Count];
  88. for (int i = 0; i < byteCode.Code.Count; i++)
  89. {
  90. source[i] = string.Format("{0:X8} {1}", i, byteCode.Code[i]);
  91. }
  92. m_Ctx.Send(o =>
  93. {
  94. codeView.SourceCode = source;
  95. }, null);
  96. }
  97. DebuggerAction m_NextAction;
  98. AutoResetEvent m_WaitLock = new AutoResetEvent(false);
  99. AutoResetEvent m_WaitBack = new AutoResetEvent(false);
  100. DebuggerAction IDebugger.GetAction(int ip)
  101. {
  102. m_Ctx.Post(o =>
  103. {
  104. codeView.ActiveLine = ip;
  105. }, null);
  106. m_WaitLock.WaitOne();
  107. DebuggerAction action = m_NextAction;
  108. m_NextAction = null;
  109. m_WaitBack.Set();
  110. return action;
  111. }
  112. void DebugAction(DebuggerAction action)
  113. {
  114. bool savedState = timerFollow.Enabled;
  115. timerFollow.Enabled = false;
  116. m_NextAction = action;
  117. m_WaitLock.Set();
  118. if (!m_WaitBack.WaitOne(1000))
  119. {
  120. MessageBox.Show(this, "Operation timed out", "Timeout");
  121. }
  122. else
  123. {
  124. timerFollow.Enabled = savedState;
  125. }
  126. }
  127. void DebugMain()
  128. {
  129. try
  130. {
  131. m_Script.Call(m_Script.GetMainChunk());
  132. }
  133. catch (ScriptRuntimeException ex)
  134. {
  135. timerFollow.Enabled = false;
  136. Console_WriteLine("Guest raised unhandled CLR exception: {0} -@{3:X8} {2}\n{1}\n", ex.GetType(), ex.ToString(), ex.DecoratedMessage, ex.InstructionPtr);
  137. }
  138. catch (Exception ex)
  139. {
  140. timerFollow.Enabled = false;
  141. Console_WriteLine("Guest raised unhandled CLR exception: {0} \n{1}\n", ex.GetType(), ex.ToString());
  142. }
  143. }
  144. private void StepIN()
  145. {
  146. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.StepIn });
  147. }
  148. private void StepOVER()
  149. {
  150. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.StepOver });
  151. }
  152. private void GO()
  153. {
  154. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Run });
  155. }
  156. void IDebugger.Update(WatchType watchType, List<WatchItem> items)
  157. {
  158. if (watchType == WatchType.CallStack)
  159. m_Ctx.Post(UpdateCallStack, items);
  160. if (watchType == WatchType.Watches)
  161. m_Ctx.Post(UpdateWatches, items);
  162. if (watchType == WatchType.VStack)
  163. m_Ctx.Post(UpdateVStack, items);
  164. }
  165. void UpdateVStack(object o)
  166. {
  167. List<WatchItem> items = (List<WatchItem>)o;
  168. lvVStack.BeginUpdate();
  169. lvVStack.Items.Clear();
  170. foreach (var item in items)
  171. {
  172. lvVStack.Add(
  173. item.Address.ToString("X4"),
  174. (item.Value != null) ? item.Value.Type.ToString() : "(undefined)",
  175. (item.Value != null) ? item.Value.ToString() : "(undefined)"
  176. ).Tag = item.Value;
  177. }
  178. lvVStack.EndUpdate();
  179. }
  180. void UpdateWatches(object o)
  181. {
  182. List<WatchItem> items = (List<WatchItem>)o;
  183. lvWatches.BeginUpdate();
  184. lvWatches.Items.Clear();
  185. foreach (var item in items)
  186. {
  187. lvWatches.Add(
  188. item.Name ?? "(???)",
  189. (item.Value != null) ? item.Value.Type.ToLuaTypeString() : "(undefined)",
  190. (item.Value != null) ? item.Value.ToString() : "(undefined)",
  191. (item.LValue != null) ? item.LValue.ToString() : "(undefined)"
  192. ).Tag = item.Value;
  193. }
  194. lvWatches.EndUpdate();
  195. }
  196. void UpdateCallStack(object o)
  197. {
  198. List<WatchItem> items = (List<WatchItem>)o;
  199. lvCallStack.BeginUpdate();
  200. lvCallStack.Items.Clear();
  201. foreach (var item in items)
  202. {
  203. lvCallStack.Add(
  204. item.Address.ToString("X8"),
  205. item.Name ?? ((item.RetAddress < 0) ? "<chunk-root>" : "<??unknown??>"),
  206. item.RetAddress.ToString("X8"),
  207. item.BasePtr.ToString("X8")
  208. ).Tag = item.Address;
  209. }
  210. lvCallStack.Add("---", "<CLR>", "---", "---");
  211. lvCallStack.EndUpdate();
  212. }
  213. List<string> IDebugger.GetWatchItems()
  214. {
  215. return m_Watches;
  216. }
  217. private void btnAddWatch_Click(object sender, EventArgs e)
  218. {
  219. string text = WatchInputDialog.GetNewWatchName();
  220. if (!string.IsNullOrEmpty(text))
  221. {
  222. m_Watches.AddRange(text.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
  223. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Refresh });
  224. }
  225. }
  226. private void btnRemoveWatch_Click(object sender, EventArgs e)
  227. {
  228. HashSet<string> itemsToRemove = new HashSet<string>(lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Text));
  229. int i = m_Watches.RemoveAll(w => itemsToRemove.Contains(w));
  230. if (i != 0)
  231. DebugAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Refresh });
  232. }
  233. private void stepInToolStripMenuItem_Click(object sender, EventArgs e)
  234. {
  235. StepIN();
  236. }
  237. private void btnOpenFile_Click(object sender, EventArgs e)
  238. {
  239. openToolStripMenuItem.PerformClick();
  240. }
  241. private void stepOverToolStripMenuItem_Click(object sender, EventArgs e)
  242. {
  243. StepOVER();
  244. }
  245. private void toolGO_Click(object sender, EventArgs e)
  246. {
  247. GO();
  248. }
  249. private void gOToolStripMenuItem_Click(object sender, EventArgs e)
  250. {
  251. GO();
  252. }
  253. private void toolStripButton1_Click(object sender, EventArgs e)
  254. {
  255. StepIN();
  256. }
  257. private void toolStepOver_Click(object sender, EventArgs e)
  258. {
  259. StepOVER();
  260. }
  261. private void btnViewVStk_Click(object sender, EventArgs e)
  262. {
  263. ValueBrowser.StartBrowse(lvVStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  264. }
  265. private void lvVStack_MouseDoubleClick(object sender, MouseEventArgs e)
  266. {
  267. ValueBrowser.StartBrowse(lvVStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  268. }
  269. private void btnViewWatch_Click(object sender, EventArgs e)
  270. {
  271. ValueBrowser.StartBrowse(lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  272. }
  273. private void lvWatches_MouseDoubleClick(object sender, MouseEventArgs e)
  274. {
  275. ValueBrowser.StartBrowse(lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault());
  276. }
  277. private void toolGoToCodeVStack_Click(object sender, EventArgs e)
  278. {
  279. var v = lvVStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault();
  280. if (v != null && v.Type == DataType.Function)
  281. GotoBytecode(v.Function.ByteCodeLocation);
  282. }
  283. private void toolGoToCodeWatches_Click(object sender, EventArgs e)
  284. {
  285. var v = lvWatches.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).Cast<DynValue>().FirstOrDefault();
  286. if (v != null && v.Type == DataType.Function)
  287. GotoBytecode(v.Function.ByteCodeLocation);
  288. }
  289. private void toolGoToCodeXStack_Click(object sender, EventArgs e)
  290. {
  291. var v = lvCallStack.SelectedItems.OfType<ListViewItem>().Select(lvi => lvi.Tag).OfType<int>().FirstOrDefault();
  292. if (v != 0)
  293. GotoBytecode(v);
  294. }
  295. private void GotoBytecode(int code)
  296. {
  297. codeView.CursorLine = code;
  298. }
  299. private void timerFollow_Tick(object sender, EventArgs e)
  300. {
  301. toolStepIN.PerformClick();
  302. }
  303. private void btnFollow_Click(object sender, EventArgs e)
  304. {
  305. timerFollow.Start();
  306. }
  307. }
  308. }