Xanathar před 11 roky
rodič
revize
b4919ad336

+ 12 - 13
src/MoonSharp.Interpreter/CoreLib/LoadMethods.cs

@@ -150,25 +150,24 @@ namespace MoonSharp.Interpreter.CoreLib
 
 		[MoonSharpMethod]
 		public const string require = @"
-			function(modulename)
-				if (package == nil) then package = { }; end
-				if (package.loaded == nil) then package.loaded = { }; end
+function(modulename)
+	if (package == nil) then package = { }; end
+	if (package.loaded == nil) then package.loaded = { }; end
 
-				local m = package.loaded[modulename];
+	local m = package.loaded[modulename];
 
-				if (m ~= nil) then
-					return m;
-				end
+	if (m ~= nil) then
+		return m;
+	end
 
-				local func = __require_clr_impl(modulename);
+	local func = __require_clr_impl(modulename);
 
-				local res = func();
+	local res = func();
 
-				package.loaded[modulename] = res;
+	package.loaded[modulename] = res;
 
-				return res;
-			end
-		";
+	return res;
+end";
 
 
 

+ 12 - 0
src/MoonSharp.Interpreter/DataTypes/DataType.cs

@@ -122,6 +122,18 @@ namespace MoonSharp.Interpreter
 			}
 		}
 
+		/// <summary>
+		/// Converts the DataType to the string returned by the "type(...)" Lua function, with additional values
+		/// to support debuggers
+		/// </summary>
+		/// <param name="type">The type.</param>
+		/// <returns></returns>
+		/// <exception cref="ScriptRuntimeException">The DataType is not a Lua type</exception>
+		public static string ToLuaDebuggerString(this DataType type)
+		{
+			return type.ToString().ToLowerInvariant();
+		}
+
 
 		/// <summary>
 		/// Converts the DataType to the string returned by the "type(...)" Lua function

+ 9 - 0
src/MoonSharp.Interpreter/Debugging/DebuggerAction.cs

@@ -19,6 +19,15 @@ namespace MoonSharp.Interpreter.Debugging
 
 		public int InstructionPtr { get; set; }
 		public ActionType Action { get; set; }
+		public DateTime TimeStampUTC { get; private set; }
+
+		public DebuggerAction()
+		{
+			TimeStampUTC = DateTime.UtcNow;
+		}
+
+		public TimeSpan Age { get { return DateTime.UtcNow - TimeStampUTC; } }
+
 
 		public override string ToString()
 		{

+ 9 - 0
src/MoonSharp.Interpreter/Debugging/WatchItem.cs

@@ -14,5 +14,14 @@ namespace MoonSharp.Interpreter.Debugging
 		public string Name { get; set; }
 		public DynValue Value { get; set; }
 		public SymbolRef LValue { get; set; }
+
+		public override string ToString()
+		{
+			return string.Format("{0}:{1}:{2}:{3}:{4}:{5}",
+				Address, BasePtr, RetAddress, Name ?? "(null)",
+				Value != null ? Value.ToString() : "(null)",
+				LValue != null ? LValue.ToString() : "(null)");
+		}
+
 	}
 }

+ 3 - 1
src/MoonSharp.Interpreter/Debugging/WatchType.cs

@@ -10,6 +10,8 @@ namespace MoonSharp.Interpreter.Debugging
 		Watches,
 		VStack,
 		CallStack,
-		Coroutines
+		Coroutines,
+
+		MaxValue
 	}
 }

+ 2 - 3
src/MoonSharp.Interpreter/Modules/ModuleRegister.cs

@@ -34,9 +34,8 @@ namespace MoonSharp.Interpreter
 		public static Table RegisterConstants(this Table table)
 		{
 			table.Set("_G", DynValue.NewTable(table));
-			table.Set("_VERSION", DynValue.NewString(string.Format("Moon# {0}", 
-				Assembly.GetExecutingAssembly().GetName().Version.Major,
-				Assembly.GetExecutingAssembly().GetName().Version.Minor)));
+			table.Set("_VERSION", DynValue.NewString(string.Format("MoonSharp {0}", 
+				Assembly.GetExecutingAssembly().GetName().Version)));
 			table.Set("_MOONSHARP", DynValue.NewString(Assembly.GetExecutingAssembly().GetName().Version.ToString()));
 
 			return table;

+ 206 - 34
src/MoonSharp.RemoteDebugger/DebugServer.cs

@@ -1,9 +1,11 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection;
 using System.Text;
 using System.Threading;
 using System.Xml;
+using MoonSharp.Interpreter;
 using MoonSharp.Interpreter.Debugging;
 using MoonSharp.RemoteDebugger.Network;
 using MoonSharp.RemoteDebugger.Threading;
@@ -13,14 +15,30 @@ namespace MoonSharp.RemoteDebugger
 	public class DebugServer : IDebugger
 	{
 		List<string> m_Watches = new List<string>();
+		List<string> m_WatchesChanging = new List<string>();
 		Utf8TcpServer m_Server;
+		Script m_Script;
+		string m_AppName;
+		object m_Lock = new object();
 
 
-		public DebugServer(int port, bool localOnly)
+		public DebugServer(string appName, Script script, int port, bool localOnly)
 		{
+			m_AppName = appName;
+
 			m_Server = new Utf8TcpServer(port, 1 << 20, '\0', localOnly ? Utf8TcpServerOptions.LocalHostOnly : Utf8TcpServerOptions.Default);
 			m_Server.Start();
 			m_Server.DataReceived += m_Server_DataReceived;
+			m_Server.ClientConnected += m_Server_ClientConnected;
+			m_Script = script;
+		}
+
+		void m_Server_ClientConnected(object sender, Utf8TcpPeerEventArgs e)
+		{
+			SendWelcome();
+
+			for (int i = 0; i < m_Script.SourceCodeCount; i++)
+				SetSourceCode(m_Script.GetSourceCode(i));
 		}
 
 		#region Writes
@@ -36,11 +54,16 @@ namespace MoonSharp.RemoteDebugger
 						.Attribute("name", sourceCode.Name);
 
 					foreach (string line in sourceCode.Lines)
-						xw.Element("l", line);
+						xw.ElementCData("l", EpurateNewLines(line));
 				}
 			});
 		}
 
+		private string EpurateNewLines(string line)
+		{
+			return line.Replace('\n', ' ').Replace('\r', ' ');
+		}
+
 
 		private void Send(Action<XmlWriter> a)
 		{
@@ -58,52 +81,105 @@ namespace MoonSharp.RemoteDebugger
 
 			a(xw);
 
+			xw.Close();
+
 			string xml = sb.ToString();
 			m_Server.BroadcastMessage(xml);
 			Console.WriteLine(xml);
 		}
 
 
-		public void Update(WatchType watchType, List<WatchItem> items)
+		private void SendWelcome()
 		{
 			Send(xw =>
 			{
-				using (xw.Element("watches"))
+				using (xw.Element("welcome"))
 				{
-					xw.Attribute("type", watchType);
+					xw.Attribute("app", m_AppName)
+						.Attribute("moonsharpver", Assembly.GetAssembly(typeof(Script)).GetName().Version.ToString());
 
-					foreach (WatchItem wi in items)
-					{
-						using (xw.Element("watch"))
-						{
-							xw.Attribute("name", wi.Name);
-							xw.Attribute("value", wi.Value);
-							xw.Attribute("address", wi.Address);
-							xw.Attribute("baseptr", wi.BasePtr);
-							xw.Attribute("lvalue", wi.LValue);
-							xw.Attribute("retaddress", wi.RetAddress);
-						}
-					}
 				}
 			});
 		}
 
-		public void SetByteCode(string[] byteCode)
+		string[] m_CachedWatches = new string[(int)WatchType.MaxValue];
+
+
+		public void Update(WatchType watchType, List<WatchItem> items)
 		{
-			Send(xw =>
+			if (watchType != WatchType.CallStack && watchType != WatchType.Watches)
+				return;
+
+			int watchIdx = (int)watchType;
+
+			string watchHash = string.Join("|", items.Select(l => l.ToString()).ToArray());
+
+			if (m_CachedWatches[watchIdx] == null || m_CachedWatches[watchIdx] != watchHash)
+			{
+				m_CachedWatches[watchIdx] = watchHash;
+
+				Send(xw =>
 				{
-					using (xw.Element("bytecode"))
+					using (xw.Element(watchType.ToString().ToLowerInvariant()))
 					{
-						foreach (string line in byteCode)
-							xw.Element("l", line);
+						foreach (WatchItem wi in items)
+						{
+							using (xw.Element("item"))
+							{
+								if (wi.Name == null)
+								{
+									if (watchType == WatchType.CallStack)
+									{
+										xw.Attribute("name", ((wi.RetAddress < 0) ? "<chunk-root>" : "<??unknown??>"));
+									}
+									else
+									{
+										xw.Attribute("name", "(null name ??)");
+									}
+								}
+								else
+								{
+									xw.Attribute("name", wi.Name);
+								}
+
+								
+
+								if (wi.Value != null)
+								{
+									xw.Attribute("value", wi.Value.ToString());
+									xw.Attribute("type", wi.Value.Type.ToLuaDebuggerString());
+								}
+
+								xw.Attribute("address", wi.Address.ToString("X8"));
+								xw.Attribute("baseptr", wi.BasePtr.ToString("X8"));
+								xw.Attribute("lvalue", wi.LValue);
+								xw.Attribute("retaddress", wi.RetAddress.ToString("X8"));
+							}
+						}
 					}
 				});
+			}
+		}
+
+		public void SetByteCode(string[] byteCode)
+		{
+			// Skip sending bytecode updates for now.
+			//Send(xw =>
+			//	{
+			//		using (xw.Element("bytecode"))
+			//		{
+			//			foreach (string line in byteCode)
+			//				xw.Element("l", line);
+			//		}
+			//	});
 		}
 
 		#endregion
 
 		BlockingQueue<DebuggerAction> m_QueuedActions = new BlockingQueue<DebuggerAction>();
 		SourceRef m_LastSentSourceRef = null;
+		bool m_InGetActionLoop = false;
+		bool m_HostBusySent = false;
 
 		public void QueueAction(DebuggerAction action)
 		{
@@ -112,27 +188,123 @@ namespace MoonSharp.RemoteDebugger
 
 		public DebuggerAction GetAction(int ip, SourceRef sourceref)
 		{
-			if (sourceref != m_LastSentSourceRef)
+			try
 			{
-				Send(xw =>
+				m_InGetActionLoop = true;
+
+				if (m_HostBusySent)
+				{
+					m_HostBusySent = false;
+					SendMessage("Host ready!");
+				}
+
+				if (sourceref != m_LastSentSourceRef)
+				{
+					Send(xw =>
+						{
+							using (xw.Element("source-loc"))
+							{
+								xw.Attribute("srcid", sourceref.SourceIdx)
+									.Attribute("cf", sourceref.FromChar)
+									.Attribute("ct", sourceref.ToChar)
+									.Attribute("lf", sourceref.FromLine)
+									.Attribute("lt", sourceref.ToLine);
+							}
+						});
+				}
+
+				while (true)
+				{
+					DebuggerAction da = m_QueuedActions.Dequeue();
+
+					if (da.Action == DebuggerAction.ActionType.Refresh)
 					{
-						using (xw.Element("source-loc"))
+						lock (m_Lock)
 						{
-							xw.Attribute("srcid", sourceref.SourceIdx)
-								.Attribute("cf", sourceref.FromChar)
-								.Attribute("ct", sourceref.ToChar)
-								.Attribute("lf", sourceref.FromLine)
-								.Attribute("lt", sourceref.ToLine);
+							m_Watches.Clear();
+							m_Watches.AddRange(m_WatchesChanging);
 						}
-					});
-			}
 
-			return m_QueuedActions.Dequeue();
+						return da;
+					}
+
+					if (da.Age < TimeSpan.FromMilliseconds(100))
+						return da;
+				}
+			}
+			finally
+			{
+				m_InGetActionLoop = false;
+			}
 		}
 
 		void m_Server_DataReceived(object sender, Utf8TcpPeerEventArgs e)
 		{
-			throw new NotImplementedException();
+			XmlDocument xdoc = new XmlDocument();
+			xdoc.LoadXml(e.Message);
+
+			if (xdoc.DocumentElement.Name == "Command")
+			{
+				string cmd = xdoc.DocumentElement.GetAttribute("cmd").ToLowerInvariant();
+				string arg = xdoc.DocumentElement.GetAttribute("arg");
+
+				switch (cmd)
+				{
+					case "stepin":
+						QueueAction(new DebuggerAction() { Action = DebuggerAction.ActionType.StepIn });
+						break;
+					case "refresh":
+						lock (m_Lock)
+						{
+							for (int i = 0; i < (int)WatchType.MaxValue; i++)
+								m_CachedWatches[i] = null;
+						}
+						QueueRefresh();
+						break;
+					case "run":
+						QueueAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Run });
+						break;
+					case "stepover":
+						QueueAction(new DebuggerAction() { Action = DebuggerAction.ActionType.StepOver });
+						break;
+					case "addwatch":
+						lock (m_Lock)
+							m_WatchesChanging.AddRange(arg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
+
+						QueueRefresh();
+						break;
+					case "delwatch":
+						lock (m_Lock)
+						{
+							var args = arg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+							foreach(var a in args)
+								m_WatchesChanging.Remove(a);
+						}
+						QueueRefresh();
+						break;
+				}
+
+			}
+		}
+
+		private void QueueRefresh()
+		{
+			if (!m_InGetActionLoop)
+			{
+				SendMessage("Host busy, wait for it to become ready...");
+				m_HostBusySent = true;
+			}
+
+			QueueAction(new DebuggerAction() { Action = DebuggerAction.ActionType.Refresh });
+		}
+
+		private void SendMessage(string text)
+		{
+			Send(xw =>
+			{
+				xw.ElementCData("message", text);
+			});
 		}
 
 

+ 20 - 14
src/MoonSharp.RemoteDebugger/Network/Utf8TcpServer.cs

@@ -86,11 +86,6 @@ namespace MoonSharp.RemoteDebugger.Network
 			}
 
 			Utf8TcpPeer peer = new Utf8TcpPeer(this, socket);
-			if (ClientConnected != null)
-			{
-				Utf8TcpPeerEventArgs args = new Utf8TcpPeerEventArgs(peer);
-				ClientConnected(this, args);
-			}
 
 			lock (m_PeerListLock)
 			{
@@ -99,6 +94,13 @@ namespace MoonSharp.RemoteDebugger.Network
 				peer.DataReceived += OnPeerDataReceived;
 			}
 
+
+			if (ClientConnected != null)
+			{
+				Utf8TcpPeerEventArgs args = new Utf8TcpPeerEventArgs(peer);
+				ClientConnected(this, args);
+			} 
+			
 			peer.Start();
 		}
 
@@ -133,21 +135,25 @@ namespace MoonSharp.RemoteDebugger.Network
 
         public void BroadcastMessage(string message)
         {
+			List<Utf8TcpPeer> peers;
+
             lock (m_PeerListLock)
             {
-				message = CompleteMessage(message);
+				peers = m_PeerList.ToList();
+			}
+
+			message = CompleteMessage(message);
 
-				if (message == null)
-					return;
+			if (message == null)
+				return;
 
-                foreach (Utf8TcpPeer peer in m_PeerList)
+			foreach (Utf8TcpPeer peer in peers)
+            {
+                try
                 {
-                    try
-                    {
-						peer.SendTerminated(message);
-                    }
-                    catch { }
+					peer.SendTerminated(message);
                 }
+                catch { }
             }
         }
 

+ 2 - 2
src/MoonSharp/Program.cs

@@ -32,7 +32,7 @@ namespace MoonSharp
 		static void Main(string[] args)
 		{
 			Console.WriteLine("Moon# {0}\nCopyright (C) 2014 Marco Mastropaolo\nhttp://www.moonsharp.org",
-				Assembly.GetExecutingAssembly().GetName().Version);
+				Assembly.GetAssembly(typeof(Script)).GetName().Version);
 
 			Console.WriteLine("Based on Lua 5.1 - 5.3, Copyright (C) 1994-2014 Lua.org");
 
@@ -135,7 +135,7 @@ namespace MoonSharp
 			}
 			if (p == "dbg")
 			{
-				m_DbgS = new DebugServer(20001, false);
+				m_DbgS = new DebugServer("MoonSharp REPL interpreter", S, 20001, false);
 				S.AttachDebugger(m_DbgS);
 			}
 		}