Эх сурвалжийг харах

coroutine fixes all around

Xanathar 11 жил өмнө
parent
commit
e9b449fc10

+ 81 - 0
src/MoonSharp.Interpreter.Tests/EndToEnd/CoroutineTests.cs

@@ -87,6 +87,87 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			Assert.AreEqual("1-5;2-6;3-7;4-8;", res.String);
 			Assert.AreEqual("1-5;2-6;3-7;4-8;", res.String);
 		}
 		}
 
 
+		[Test]
+		public void Coroutine_ClrBoundaryHandling()
+		{
+			string code = @"
+				function a()
+					callback(b)
+				end
+
+				function b()
+					coroutine.yield();
+				end						
+
+				c = coroutine.create(a);
+
+				return coroutine.resume(c);		
+				";
+
+			// Load the code and get the returned function
+			Script script = new Script();
+
+			script.Globals["callback"] = DynValue.NewCallback(
+				(ctx, args) => args[0].Function.Call()
+				);
+
+			DynValue ret = script.DoString(code);
+
+			Assert.AreEqual(DataType.Tuple, ret.Type);
+			Assert.AreEqual(2, ret.Tuple.Length);
+			Assert.AreEqual(DataType.Boolean, ret.Tuple[0].Type);
+			Assert.AreEqual(false, ret.Tuple[0].Boolean);
+			Assert.AreEqual(DataType.String, ret.Tuple[1].Type);
+			Assert.AreEqual("attempt to yield across a CLR-call boundary", ret.Tuple[1].String);
+		}
+
+		[Test]
+		public void Coroutine_VariousErrorHandling()
+		{
+			string code = @"
+
+function checkresume(step, ex, ey)
+	local x, y = coroutine.resume(c)
+	
+	assert(x == ex, 'Step ' .. step .. ': ' .. tostring(ex) .. ' was expected, got ' .. tostring(x));
+	assert(y == ey, 'Step ' .. step .. ': ' .. tostring(ey) .. ' was expected, got ' .. tostring(y));
+end
+
+
+t = { }
+m = { __tostring = function() print('2'); coroutine.yield(); print('3'); end }
+
+setmetatable(t, m);
+
+
+function a()
+	checkresume(1, false, 'cannot resume non-suspended coroutine');
+	coroutine.yield('ok');
+	print(t);
+	coroutine.yield('ok'); 
+end
+
+c = coroutine.create(a);
+
+checkresume(2, true, 'ok');
+checkresume(3, false, 'attempt to yield across a CLR-call boundary');
+checkresume(4, false, 'cannot resume dead coroutine');
+checkresume(5, false, 'cannot resume dead coroutine');
+checkresume(6, false, 'cannot resume dead coroutine');
+
+				";
+
+			// Load the code and get the returned function
+			Script script = new Script();
+
+			script.DoString(code);
+		}
+
+
+
+
+
+
 
 
 	}
 	}
 }
 }

+ 0 - 17
src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs

@@ -968,23 +968,6 @@ namespace MoonSharp.Interpreter.Tests
 		}
 		}
 
 
 
 
-		[Test]
-		public void PCallOnClrFunction()
-		{
-			string script = @"
-				r, msg = pcall(assert, false, 'catched')
-				return r, msg;
-								";
-
-			DynValue res = Script.RunString(script);
-
-			Assert.AreEqual(DataType.Tuple, res.Type);
-			Assert.AreEqual(2, res.Tuple.Length);
-			Assert.AreEqual(DataType.Boolean, res.Tuple[0].Type);
-			Assert.AreEqual(DataType.String, res.Tuple[1].Type);
-			Assert.AreEqual(false, res.Tuple[0].Boolean);
-		}
-
 		[Test]
 		[Test]
 		public void ArgsDoNotChange()
 		public void ArgsDoNotChange()
 		{
 		{

+ 1 - 0
src/MoonSharp.Interpreter.Tests/MoonSharp.Interpreter.Tests.csproj

@@ -91,6 +91,7 @@
       <SubType>Code</SubType>
       <SubType>Code</SubType>
     </Compile>
     </Compile>
     <Compile Include="EndToEnd\Utils.cs" />
     <Compile Include="EndToEnd\Utils.cs" />
+    <Compile Include="ErrorHandlingTests.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="EndToEnd\SimpleTests.cs" />
     <Compile Include="EndToEnd\SimpleTests.cs" />
     <Compile Include="EndToEnd\TableTests.cs" />
     <Compile Include="EndToEnd\TableTests.cs" />

+ 1 - 0
src/MoonSharp.Interpreter/CoreLib/CoroutineModule.cs

@@ -55,6 +55,7 @@ namespace MoonSharp.Interpreter.CoreLib
 					for (int i = 0; i < ret.Tuple.Length; i++)
 					for (int i = 0; i < ret.Tuple.Length; i++)
 					{
 					{
 						var v = ret.Tuple[i];
 						var v = ret.Tuple[i];
+
 						if ((i == ret.Tuple.Length - 1) && (v.Type == DataType.Tuple))
 						if ((i == ret.Tuple.Length - 1) && (v.Type == DataType.Tuple))
 						{
 						{
 							retval.AddRange(v.Tuple);
 							retval.AddRange(v.Tuple);

+ 0 - 1
src/MoonSharp.Interpreter/DataTypes/DynValue.cs

@@ -859,7 +859,6 @@ namespace MoonSharp.Interpreter
 			throw ScriptRuntimeException.BadArgumentUserData(argNum, funcName, typeof(T), o, allowNil);
 			throw ScriptRuntimeException.BadArgumentUserData(argNum, funcName, typeof(T), o, allowNil);
 		}
 		}
 
 
-
 	}
 	}
 
 
 
 

+ 2 - 0
src/MoonSharp.Interpreter/DataTypes/Table.cs

@@ -461,5 +461,7 @@ namespace MoonSharp.Interpreter
 
 
 
 
 
 
+
+
 	}
 	}
 }
 }

+ 47 - 0
src/MoonSharp.Interpreter/Debugging/IDebugger.cs

@@ -6,16 +6,63 @@ using MoonSharp.Interpreter.Execution.VM;
 
 
 namespace MoonSharp.Interpreter.Debugging
 namespace MoonSharp.Interpreter.Debugging
 {
 {
+	/// <summary>
+	/// Interface for debuggers to implement, in order to provide debugging facilities to Scripts.
+	/// </summary>
 	public interface IDebugger
 	public interface IDebugger
 	{
 	{
+		/// <summary>
+		/// Called by the script engine  when a source code is added or changed.
+		/// </summary>
+		/// <param name="sourceCode">The source code object.</param>
 		void SetSourceCode(SourceCode sourceCode);
 		void SetSourceCode(SourceCode sourceCode);
+		/// <summary>
+		/// Called by the script engine  when the bytecode changes.
+		/// </summary>
+		/// <param name="byteCode">The bytecode source</param>
 		void SetByteCode(string[] byteCode);
 		void SetByteCode(string[] byteCode);
+		/// <summary>
+		/// Called by the script engine at execution time to check if a break has 
+		/// been requested. Should return pretty fast as it's called A LOT.
+		/// </summary>
 		bool IsPauseRequested();
 		bool IsPauseRequested();
+		/// <summary>
+		/// Called by the script engine when a runtime error occurs. 
+		/// The debugger can return true to signal the engine that it wants to break 
+		/// into the source of the error. If it does so, it should also return true 
+		/// to subsequent calls to IsPauseRequested().
+		/// </summary>
+		/// <param name="ex">The runtime exception.</param>
+		/// <returns>True if this error should break execution.</returns>
 		bool SignalRuntimeException(ScriptRuntimeException ex);
 		bool SignalRuntimeException(ScriptRuntimeException ex);
+		/// <summary>
+		/// Called by the script engine to get what action to do next.
+		/// </summary>
+		/// <param name="ip">The instruction pointer in bytecode.</param>
+		/// <param name="sourceref">The source reference.</param>
+		/// <returns>T</returns>
 		DebuggerAction GetAction(int ip, SourceRef sourceref);
 		DebuggerAction GetAction(int ip, SourceRef sourceref);
+		/// <summary>
+		/// Called by the script engine when the execution ends.
+		/// </summary>
 		void SignalExecutionEnded();
 		void SignalExecutionEnded();
+		/// <summary>
+		/// Called by the script engine to update watches of a given type. Note 
+		/// that this method is not called only for watches in the strictest term, 
+		/// but also for the stack, etc.
+		/// </summary>
+		/// <param name="watchType">Type of the watch.</param>
+		/// <param name="items">The items.</param>
 		void Update(WatchType watchType, IEnumerable<WatchItem> items);
 		void Update(WatchType watchType, IEnumerable<WatchItem> items);
+		/// <summary>
+		/// Called by the script engine to get which expressions are active 
+		/// watches in the debugger.
+		/// </summary>
+		/// <returns>A list of watches</returns>
 		List<DynamicExpression> GetWatchItems();
 		List<DynamicExpression> GetWatchItems();
+		/// <summary>
+		/// Called by the script engine to refresh the breakpoint list.
+		/// </summary>
 		void RefreshBreakpoints(IEnumerable<SourceRef> refs);
 		void RefreshBreakpoints(IEnumerable<SourceRef> refs);
 	}
 	}
 }
 }

+ 1 - 1
src/MoonSharp.Interpreter/Errors/ScriptRuntimeException.cs

@@ -186,7 +186,7 @@ namespace MoonSharp.Interpreter
 
 
 		public static ScriptRuntimeException CannotYield()
 		public static ScriptRuntimeException CannotYield()
 		{
 		{
-			return new ScriptRuntimeException("cannot yield to parent coroutine as it would cross a script-clr boundary");
+			return new ScriptRuntimeException("attempt to yield across a CLR-call boundary");
 		}
 		}
 
 
 		public static ScriptRuntimeException CannotYieldMain()
 		public static ScriptRuntimeException CannotYieldMain()

+ 2 - 0
src/MoonSharp.Interpreter/Execution/VM/CallStackItem.cs

@@ -22,6 +22,8 @@ namespace MoonSharp.Interpreter.Execution.VM
 		public int ReturnAddress;
 		public int ReturnAddress;
 		public DynValue[] LocalScope;
 		public DynValue[] LocalScope;
 		public ClosureContext ClosureScope;
 		public ClosureContext ClosureScope;
+
+		public CallStackItemFlags Flags;
 	}
 	}
 
 
 }
 }

+ 22 - 3
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs

@@ -14,6 +14,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 		FastStack<DynValue> m_ValueStack = new FastStack<DynValue>(131072);
 		FastStack<DynValue> m_ValueStack = new FastStack<DynValue>(131072);
 		FastStack<CallStackItem> m_ExecutionStack = new FastStack<CallStackItem>(131072);
 		FastStack<CallStackItem> m_ExecutionStack = new FastStack<CallStackItem>(131072);
+		List<Processor> m_CoroutinesStack;
 
 
 		Table m_GlobalTable;
 		Table m_GlobalTable;
 		Script m_Script;
 		Script m_Script;
@@ -25,6 +26,8 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 		public Processor(Script script, Table globalContext, ByteCode byteCode)
 		public Processor(Script script, Table globalContext, ByteCode byteCode)
 		{
 		{
+			m_CoroutinesStack = new List<Processor>();
+
 			m_Debug = new DebugContext();
 			m_Debug = new DebugContext();
 			m_RootChunk = byteCode;
 			m_RootChunk = byteCode;
 			m_GlobalTable = globalContext;
 			m_GlobalTable = globalContext;
@@ -47,6 +50,11 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 		public DynValue Call(DynValue function, DynValue[] args)
 		public DynValue Call(DynValue function, DynValue[] args)
 		{
 		{
+			List<Processor> coroutinesStack = m_Parent != null ? m_Parent.m_CoroutinesStack : this.m_CoroutinesStack;
+
+			if (coroutinesStack.Count > 0 && coroutinesStack[coroutinesStack.Count - 1] != this)
+				return coroutinesStack[coroutinesStack.Count - 1].Call(function, args);
+
 			EnterProcessor();
 			EnterProcessor();
 
 
 			try
 			try
@@ -57,7 +65,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 				try
 				try
 				{
 				{
-					int entrypoint = PushClrToScriptStackFrame(function, args);
+					int entrypoint = PushClrToScriptStackFrame(CallStackItemFlags.CallEntryPoint, function, args);
 					return Processing_Loop(entrypoint);
 					return Processing_Loop(entrypoint);
 				}
 				}
 				finally
 				finally
@@ -76,7 +84,7 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 		// pushes all what's required to perform a clr-to-script function call. function can be null if it's already
 		// pushes all what's required to perform a clr-to-script function call. function can be null if it's already
 		// at vstack top.
 		// at vstack top.
-		private int PushClrToScriptStackFrame(DynValue function, DynValue[] args)
+		private int PushClrToScriptStackFrame(CallStackItemFlags flags, DynValue function, DynValue[] args)
 		{
 		{
 			if (function == null) 
 			if (function == null) 
 				function = m_ValueStack.Peek();
 				function = m_ValueStack.Peek();
@@ -96,7 +104,8 @@ namespace MoonSharp.Interpreter.Execution.VM
 				Debug_EntryPoint = function.Function.EntryPointByteCodeLocation,
 				Debug_EntryPoint = function.Function.EntryPointByteCodeLocation,
 				ReturnAddress = -1,
 				ReturnAddress = -1,
 				ClosureScope = function.Function.ClosureContext,
 				ClosureScope = function.Function.ClosureContext,
-				CallingSourceRef = SourceRef.GetClrLocation()
+				CallingSourceRef = SourceRef.GetClrLocation(),
+				Flags = flags
 			});
 			});
 
 
 			return function.Function.EntryPointByteCodeLocation;
 			return function.Function.EntryPointByteCodeLocation;
@@ -110,6 +119,11 @@ namespace MoonSharp.Interpreter.Execution.VM
 		{
 		{
 			m_ExecutionNesting -= 1;
 			m_ExecutionNesting -= 1;
 
 
+			if (m_Parent != null)
+			{
+				m_Parent.m_CoroutinesStack.RemoveAt(m_Parent.m_CoroutinesStack.Count - 1);
+			}
+
 			if (m_ExecutionNesting == 0 && m_Debug != null && m_Debug.DebuggerAttached != null)
 			if (m_ExecutionNesting == 0 && m_Debug != null && m_Debug.DebuggerAttached != null)
 			{
 			{
 				m_Debug.DebuggerAttached.SignalExecutionEnded();
 				m_Debug.DebuggerAttached.SignalExecutionEnded();
@@ -129,6 +143,11 @@ namespace MoonSharp.Interpreter.Execution.VM
 			m_OwningThreadID = threadID;
 			m_OwningThreadID = threadID;
 
 
 			m_ExecutionNesting += 1;
 			m_ExecutionNesting += 1;
+
+			if (m_Parent != null)
+			{
+				m_Parent.m_CoroutinesStack.Add(this);
+			}
 		}
 		}
 
 
 		internal SourceRef GetCoroutineSuspendedLocation()
 		internal SourceRef GetCoroutineSuspendedLocation()

+ 9 - 1
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_Coroutines.cs

@@ -39,7 +39,9 @@ namespace MoonSharp.Interpreter.Execution.VM
 					throw ScriptRuntimeException.CannotResumeNotSuspended(m_State);
 					throw ScriptRuntimeException.CannotResumeNotSuspended(m_State);
 
 
 				if (m_State == CoroutineState.NotStarted)
 				if (m_State == CoroutineState.NotStarted)
-					entrypoint = PushClrToScriptStackFrame(null, args);
+				{
+					entrypoint = PushClrToScriptStackFrame(CallStackItemFlags.ResumeEntryPoint, null, args);
+				}
 				else
 				else
 				{
 				{
 					m_ValueStack.Push(DynValue.NewTuple(args));
 					m_ValueStack.Push(DynValue.NewTuple(args));
@@ -60,6 +62,12 @@ namespace MoonSharp.Interpreter.Execution.VM
 					return retVal;
 					return retVal;
 				}
 				}
 			}
 			}
+			catch (Exception)
+			{
+				// Unhandled exception - move to dead
+				m_State = CoroutineState.Dead;
+				throw;
+			}
 			finally
 			finally
 			{
 			{
 				LeaveProcessor();
 				LeaveProcessor();

+ 5 - 5
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor_InstructionLoop.cs

@@ -276,13 +276,13 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 
 						goto repeat_execution;
 						goto repeat_execution;
 					}
 					}
+					else if ((csi.Flags & CallStackItemFlags.EntryPoint) != 0)
+					{
+						throw;
+					}
 				}
 				}
 
 
-				if (m_ExecutionStack.Count == 0)
-				{
-					throw;
-				}
-
+				throw;
 			}
 			}
 
 
 		return_to_native_code:
 		return_to_native_code:

+ 11 - 0
src/MoonSharp.Interpreter/Interop/Portable.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop
+{
+	public class Portable
+	{
+	}
+}

+ 2 - 0
src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj

@@ -103,6 +103,7 @@
     <Compile Include="DataTypes\TypeValidationFlags.cs" />
     <Compile Include="DataTypes\TypeValidationFlags.cs" />
     <Compile Include="Errors\DynamicExpressionException.cs" />
     <Compile Include="Errors\DynamicExpressionException.cs" />
     <Compile Include="Execution\DynamicExpression.cs" />
     <Compile Include="Execution\DynamicExpression.cs" />
+    <Compile Include="Execution\VM\CallStackItemFlags.cs" />
     <Compile Include="Interop\AnonWrapper.cs" />
     <Compile Include="Interop\AnonWrapper.cs" />
     <Compile Include="Interop\LuaStateInterop\CharPtr.cs" />
     <Compile Include="Interop\LuaStateInterop\CharPtr.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaBase.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaBase.cs" />
@@ -178,6 +179,7 @@
     <Compile Include="Interop\LuaStateInterop\LuaState.cs" />
     <Compile Include="Interop\LuaStateInterop\LuaState.cs" />
     <Compile Include="Interop\MoonSharpUserDataAttribute.cs" />
     <Compile Include="Interop\MoonSharpUserDataAttribute.cs" />
     <Compile Include="Interop\MoonSharpVisibleAttribute.cs" />
     <Compile Include="Interop\MoonSharpVisibleAttribute.cs" />
+    <Compile Include="Interop\Portable.cs" />
     <Compile Include="Interop\UserDataDelegateDescriptor.cs" />
     <Compile Include="Interop\UserDataDelegateDescriptor.cs" />
     <Compile Include="Interop\UserDataDescriptor.cs" />
     <Compile Include="Interop\UserDataDescriptor.cs" />
     <Compile Include="DataTypes\InteropAccessMode.cs" />
     <Compile Include="DataTypes\InteropAccessMode.cs" />

+ 1 - 1
src/PerformanceComparison/CallbacksAndForthTests.cs

@@ -36,7 +36,7 @@ namespace PerformanceComparison
 
 
 	class CallbacksAndForthTests
 	class CallbacksAndForthTests
 	{
 	{
-		public static void Main()
+		public static void xxMain()
 		{
 		{
 			(new CallbacksAndForthTests()).Start();
 			(new CallbacksAndForthTests()).Start();
 			//Console.ReadLine();
 			//Console.ReadLine();

+ 83 - 0
src/PerformanceComparison/CoroutineTest.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices.ComTypes;
+using System.Text;
+using System.Threading.Tasks;
+using MoonSharp.Interpreter;
+
+namespace PerformanceComparison
+{
+	class CoroutineTest
+	{
+		public static void xMain()
+		{
+			string code = @"
+				return function()
+					local x = 0
+					while true do
+						x = x + 1
+						coroutine.yield(x)
+					end
+				end
+				";
+
+			// Load the code and get the returned function
+			Script script = new Script();
+			DynValue function = script.DoString(code);
+
+			// Create the coroutine in C#
+			DynValue coroutine = script.CreateCoroutine(function);
+
+			// Resume the coroutine forever and ever..
+			while (true)
+			{
+				DynValue x = coroutine.Coroutine.Resume();
+				Console.WriteLine("{0}", x);
+			}
+
+
+			Console.ReadKey();
+		}
+
+
+		public static void xxMain()
+		{
+			string code = @"
+				function a()
+					callback(b)
+				end
+
+				function b()
+					coroutine.yield();
+				end						
+
+				c = coroutine.create(a);
+
+				return coroutine.resume(c);		
+				";
+
+			// Load the code and get the returned function
+			Script script = new Script();
+
+			script.Globals["callback"] = DynValue.NewCallback(
+				(ctx, args) => args[0].Function.Call()
+				);
+
+			DynValue ret = script.DoString(code);
+
+			// false, "attempt to yield from outside a coroutine"
+			Console.WriteLine(ret);
+
+			
+
+			Console.ReadKey();
+		}
+
+
+
+
+
+
+	}
+}

+ 4 - 0
src/PerformanceComparison/PerformanceComparison.csproj

@@ -81,9 +81,13 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="CallbacksAndForthTests.cs" />
     <Compile Include="CallbacksAndForthTests.cs" />
+    <Compile Include="CoroutineTest.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="HugeFile.cs" />
     <Compile Include="HugeFile.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Sample.cs" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj">
     <ProjectReference Include="..\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj">

+ 56 - 0
src/PerformanceComparison/Sample.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MoonSharp.Interpreter;
+
+namespace PerformanceComparison
+{
+	class Sample
+	{
+
+		// This prints :
+		//     3
+		//     hello world
+		//     3
+		//     hello world
+		//     3
+		//     hello world
+		//     3
+		//     hello world
+		//     Done
+		public static void Main()
+		{
+			string code = @"
+				x = 3
+
+				function onThis()
+					print(x)
+					x = 'hello'
+				end
+
+				function onThat()
+					print(x .. ' world')
+					x = 3
+				end						
+				";
+
+			// Load the code 
+			Script script = new Script();
+			script.DoString(code);
+
+			var onThis = script.Globals.Get("onThis").Function.GetDelegate();
+			var onThat = script.Globals.Get("onThat").Function.GetDelegate();
+
+			for (int i = 0; i < 4; i++)
+			{
+				onThis();
+				onThat();
+			}
+
+			Console.WriteLine("Done");
+			Console.ReadKey();
+		}
+	}
+}

+ 20 - 0
src/moonsharp.sln

@@ -25,6 +25,16 @@ Project("{7CF6DF6D-3B04-46F8-A40B-537D21BCA0B4}") = "MoonSharp.Documentation", "
 EndProject
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoonSharp.RemoteDebugger", "MoonSharp.RemoteDebugger\MoonSharp.RemoteDebugger.csproj", "{43D3AD52-FED5-4305-B0F4-6B991220CD0A}"
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoonSharp.RemoteDebugger", "MoonSharp.RemoteDebugger\MoonSharp.RemoteDebugger.csproj", "{43D3AD52-FED5-4305-B0F4-6B991220CD0A}"
 EndProject
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DevTools", "DevTools", "{3C626068-E8CE-4F62-8974-F42A56F4EFD3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interpreters", "Interpreters", "{16A9EA72-79A5-448D-B7A3-55E7D8362479}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RemoteDebuggers", "RemoteDebuggers", "{5014C740-F6C7-4995-8D40-C250FB159A20}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Distribution", "Distribution", "{59F722D5-6E5C-4544-A849-18E7CE876FDF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FA582319-EA17-4C52-870D-C00EF793628F}"
+EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Debug|Any CPU = Debug|Any CPU
@@ -95,4 +105,14 @@ Global
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{2A4BD262-D6EB-4611-A28B-27B6DAEB089B} = {59F722D5-6E5C-4544-A849-18E7CE876FDF}
+		{91EA9B9D-FE03-4273-BDAF-8AD42EDE1E59} = {16A9EA72-79A5-448D-B7A3-55E7D8362479}
+		{4AD350E6-E296-43EF-9FEA-CB70358467E4} = {FA582319-EA17-4C52-870D-C00EF793628F}
+		{01C3C379-C816-4779-942D-0263763F8EA5} = {3C626068-E8CE-4F62-8974-F42A56F4EFD3}
+		{470C034F-1F1F-499C-9499-DC00B9EEEDE9} = {3C626068-E8CE-4F62-8974-F42A56F4EFD3}
+		{F4F82CCE-2E13-441B-939C-63CF2343B1C9} = {3C626068-E8CE-4F62-8974-F42A56F4EFD3}
+		{26B3033C-D1E2-4188-870C-D197E95A7F6B} = {59F722D5-6E5C-4544-A849-18E7CE876FDF}
+		{43D3AD52-FED5-4305-B0F4-6B991220CD0A} = {5014C740-F6C7-4995-8D40-C250FB159A20}
+	EndGlobalSection
 EndGlobal
 EndGlobal