From 1449e0637ce7f623d7a26415094c487de200112c Mon Sep 17 00:00:00 2001 From: Robin Rolf Date: Tue, 9 Jun 2020 10:03:08 +0200 Subject: [PATCH 1/2] Proof of concept for enumerator clr coroutines --- .../MoonSharpClrCoroutineAttribute.cs | 15 +++++++ .../DispatchingUserDataDescriptor.cs | 2 +- .../MethodMemberDescriptorCoroutine.cs | 44 +++++++++++++++++++ .../StandardUserDataDescriptor.cs | 7 ++- 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpClrCoroutineAttribute.cs create mode 100644 src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs diff --git a/src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpClrCoroutineAttribute.cs b/src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpClrCoroutineAttribute.cs new file mode 100644 index 00000000..8a1d6261 --- /dev/null +++ b/src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpClrCoroutineAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace MoonSharp.Interpreter +{ + /// + /// Marks a method as a clr enumerator based coroutine + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true)] + public sealed class MoonSharpClrCoroutineAttribute : Attribute + { + public MoonSharpClrCoroutineAttribute() + { + } + } +} \ No newline at end of file diff --git a/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs b/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs index 8867be86..18a92f62 100644 --- a/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs +++ b/src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs @@ -178,7 +178,7 @@ private void AddMemberTo(Dictionary members, string n { IOverloadableMemberDescriptor odesc = desc as IOverloadableMemberDescriptor; - if (odesc != null) + if (odesc != null && !(desc is MethodMemberDescriptorCoroutine)) { if (members.ContainsKey(name)) { diff --git a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs new file mode 100644 index 00000000..4b34facc --- /dev/null +++ b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs @@ -0,0 +1,44 @@ +using System.Reflection; + +namespace MoonSharp.Interpreter.Interop +{ + public class MethodMemberDescriptorCoroutine : MethodMemberDescriptor + { + public MethodMemberDescriptorCoroutine(MethodBase methodBase, InteropAccessMode accessMode = InteropAccessMode.Default) : base(methodBase, accessMode) + { + } + + public override DynValue GetValue(Script script, object obj) + { + var enumerateYielder = script.DoString(@"return function (callable) + return function (...) + for y in callable(...) do + coroutine.yield(y) + end + end +end"); + return script.Call(enumerateYielder, base.GetValue(script, obj)); + } + + /// Tries to create a new MethodMemberDescriptorCoroutine, returning + /// null in case the method is not + /// visible to script code. + /// + /// The MethodBase. + /// The + /// if set to true forces visibility. + /// + /// A new MethodMemberDescriptor or null. + /// + public static MethodMemberDescriptorCoroutine TryCreateCoroutineIfVisible(MethodBase methodBase, InteropAccessMode accessMode, bool forceVisibility = false) + { + if (!CheckMethodIsCompatible(methodBase, false)) + return null; + + if (forceVisibility || (methodBase.GetVisibilityFromAttributes() ?? methodBase.IsPublic)) + return new MethodMemberDescriptorCoroutine(methodBase, accessMode); + + return null; + } + } +} \ No newline at end of file diff --git a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataDescriptor.cs b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataDescriptor.cs index 6eece605..0bb97c2c 100755 --- a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataDescriptor.cs +++ b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/StandardUserDataDescriptor.cs @@ -78,7 +78,12 @@ private void FillMemberList() { if (membersToIgnore.Contains(mi.Name)) continue; - MethodMemberDescriptor md = MethodMemberDescriptor.TryCreateIfVisible(mi, this.AccessMode); + MethodMemberDescriptor md; + if (mi.CustomAttributes.Any(data => data.AttributeType == typeof(MoonSharpClrCoroutineAttribute))) { + md = MethodMemberDescriptorCoroutine.TryCreateCoroutineIfVisible(mi, this.AccessMode); + } else { + md = MethodMemberDescriptor.TryCreateIfVisible(mi, this.AccessMode); + } if (md != null) { From 66ffb65dcb352a0d40d44e2ccf1515a04018b02b Mon Sep 17 00:00:00 2001 From: Robin Rolf Date: Tue, 9 Jun 2020 13:10:17 +0200 Subject: [PATCH 2/2] Return values --- .../CoreLib/CoroutineModule.cs | 13 ++++++++++++- src/MoonSharp.Interpreter/DataTypes/DataType.cs | 8 ++++++++ src/MoonSharp.Interpreter/DataTypes/DynValue.cs | 13 +++++++++++++ .../MethodMemberDescriptorCoroutine.cs | 8 ++++++-- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/MoonSharp.Interpreter/CoreLib/CoroutineModule.cs b/src/MoonSharp.Interpreter/CoreLib/CoroutineModule.cs index d405a88e..c01facc6 100644 --- a/src/MoonSharp.Interpreter/CoreLib/CoroutineModule.cs +++ b/src/MoonSharp.Interpreter/CoreLib/CoroutineModule.cs @@ -121,7 +121,18 @@ public static DynValue status(ScriptExecutionContext executionContext, CallbackA } } - + + [MoonSharpModuleMethod] + public static DynValue is_return_value(ScriptExecutionContext executionContext, CallbackArguments args) + { + return args[0].Type == DataType.ClrCoroutineReturn ? DynValue.True : DynValue.False; + } + + [MoonSharpModuleMethod] + public static DynValue get_return_value(ScriptExecutionContext executionContext, CallbackArguments args) + { + return args[0].Type == DataType.ClrCoroutineReturn ? args[0].ClrCoroutineReturnValue : DynValue.Nil; + } } } diff --git a/src/MoonSharp.Interpreter/DataTypes/DataType.cs b/src/MoonSharp.Interpreter/DataTypes/DataType.cs index 46694a6e..220b2f54 100644 --- a/src/MoonSharp.Interpreter/DataTypes/DataType.cs +++ b/src/MoonSharp.Interpreter/DataTypes/DataType.cs @@ -64,6 +64,10 @@ public enum DataType /// A request to coroutine.yield /// YieldRequest, + /// + /// Return a value from a clr coroutine + /// + ClrCoroutineReturn, } /// @@ -114,6 +118,8 @@ public static string ToErrorTypeString(this DataType type) return "userdata"; case DataType.Thread: return "coroutine"; + case DataType.ClrCoroutineReturn: + return "coroutine_return"; case DataType.Tuple: case DataType.TailCallRequest: case DataType.YieldRequest: @@ -164,6 +170,8 @@ public static string ToLuaTypeString(this DataType type) return "userdata"; case DataType.Thread: return "thread"; + case DataType.ClrCoroutineReturn: + return "coroutine_return"; case DataType.Tuple: case DataType.TailCallRequest: case DataType.YieldRequest: diff --git a/src/MoonSharp.Interpreter/DataTypes/DynValue.cs b/src/MoonSharp.Interpreter/DataTypes/DynValue.cs index 9df80fe0..4af0dfbf 100644 --- a/src/MoonSharp.Interpreter/DataTypes/DynValue.cs +++ b/src/MoonSharp.Interpreter/DataTypes/DynValue.cs @@ -76,6 +76,11 @@ public sealed class DynValue /// Gets the tail call data. /// public UserData UserData { get { return m_Object as UserData; } } + + /// + /// Gets the clr couroutine return value + /// + public DynValue ClrCoroutineReturnValue { get { return m_Object as DynValue; } } /// /// Returns true if this instance is write protected. @@ -373,6 +378,14 @@ public static DynValue NewUserData(UserData userData) }; } + public static DynValue NewClrCoroutineReturn(DynValue returnedValue) { + return new DynValue() + { + m_Object = returnedValue, + m_Type = DataType.ClrCoroutineReturn, + }; + } + /// /// Returns this value as readonly - eventually cloning it in the process if it isn't readonly to start with. /// diff --git a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs index 4b34facc..d1de80e2 100644 --- a/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs +++ b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs @@ -13,10 +13,14 @@ public override DynValue GetValue(Script script, object obj) var enumerateYielder = script.DoString(@"return function (callable) return function (...) for y in callable(...) do - coroutine.yield(y) + if coroutine.is_return_value(y) then + return coroutine.get_return_value(y) + else + coroutine.yield(y) + end end end -end"); +end", null, MethodInfo + "_yielder"); return script.Call(enumerateYielder, base.GetValue(script, obj)); }