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/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..d1de80e2 --- /dev/null +++ b/src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs @@ -0,0 +1,48 @@ +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 + if coroutine.is_return_value(y) then + return coroutine.get_return_value(y) + else + coroutine.yield(y) + end + end + end +end", null, MethodInfo + "_yielder"); + 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) {