Browse Source

Add: CsClosure

Akeit0 9 months ago
parent
commit
dee257d154

+ 19 - 14
src/Lua/LuaFunctionExecutionContext.cs

@@ -1,6 +1,7 @@
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using Lua.CodeAnalysis;
+using Lua.Runtime;
 
 namespace Lua;
 
@@ -19,10 +20,7 @@ public readonly record struct LuaFunctionExecutionContext
 
     public ReadOnlySpan<LuaValue> Arguments
     {
-        get
-        {
-            return Thread.GetStackValues().Slice(FrameBase, ArgumentCount);
-        }
+        get { return Thread.GetStackValues().Slice(FrameBase, ArgumentCount); }
     }
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -37,7 +35,7 @@ public readonly record struct LuaFunctionExecutionContext
         ThrowIfArgumentNotExists(index);
         return Arguments[index];
     }
-    
+
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     internal LuaValue GetArgumentOrDefault(int index, LuaValue defaultValue = default)
     {
@@ -45,6 +43,7 @@ public readonly record struct LuaFunctionExecutionContext
         {
             return defaultValue;
         }
+
         return Arguments[index];
     }
 
@@ -65,9 +64,9 @@ public readonly record struct LuaFunctionExecutionContext
             {
                 LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, type.ToString(), arg.Type.ToString());
             }
-            else if(arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
+            else if (arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
             {
-                LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.UnsafeRead<object>()?.GetType().ToString()??"userdata: 0");
+                LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.UnsafeRead<object>()?.GetType().ToString() ?? "userdata: 0");
             }
             else
             {
@@ -79,7 +78,7 @@ public readonly record struct LuaFunctionExecutionContext
     }
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    internal T GetArgumentOrDefault<T>(int index,T defaultValue =default!) 
+    internal T GetArgumentOrDefault<T>(int index, T defaultValue = default!)
     {
         if (ArgumentCount <= index)
         {
@@ -87,12 +86,12 @@ public readonly record struct LuaFunctionExecutionContext
         }
 
         var arg = Arguments[index];
-        
-        if(arg.Type is LuaValueType.Nil)
+
+        if (arg.Type is LuaValueType.Nil)
         {
             return defaultValue;
         }
-        
+
         if (!arg.TryRead<T>(out var argValue))
         {
             var t = typeof(T);
@@ -104,9 +103,9 @@ public readonly record struct LuaFunctionExecutionContext
             {
                 LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, type.ToString(), arg.Type.ToString());
             }
-            else if(arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
+            else if (arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
             {
-                LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.UnsafeRead<object>()?.GetType().ToString()??"userdata: 0");
+                LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.UnsafeRead<object>()?.GetType().ToString() ?? "userdata: 0");
             }
             else
             {
@@ -116,7 +115,13 @@ public readonly record struct LuaFunctionExecutionContext
 
         return argValue;
     }
-    
+
+    public CsClosure? GetCsClosure()
+    {
+        var stack = Thread.CallStack[^1];
+        return stack.Function as CsClosure;
+    }
+
     internal void ThrowBadArgument(int index, string message)
     {
         LuaRuntimeException.BadArgument(State.GetTraceback(), index, Thread.GetCurrentFrame().Function.Name, message);

+ 6 - 0
src/Lua/Runtime/CsClosure.cs

@@ -0,0 +1,6 @@
+namespace Lua.Runtime;
+
+public sealed class CsClosure(string name,LuaValue[] upValues,Func<LuaFunctionExecutionContext, Memory<LuaValue>, CancellationToken, ValueTask<int>> func) : LuaFunction(name, func)
+{
+   public readonly LuaValue[] UpValues = upValues;
+}

+ 5 - 2
src/Lua/Standard/CoroutineLibrary.cs

@@ -1,3 +1,5 @@
+using Lua.Runtime;
+
 namespace Lua.Standard;
 
 public sealed class CoroutineLibrary
@@ -57,8 +59,9 @@ public sealed class CoroutineLibrary
         var arg0 = context.GetArgument<LuaFunction>(0);
         var thread = new LuaCoroutine(arg0, false);
 
-        buffer.Span[0] = new LuaFunction("wrap", async (context, buffer, cancellationToken) =>
+        buffer.Span[0] = new CsClosure("wrap", [thread],static async (context, buffer, cancellationToken) =>
         {
+            var thread = context.GetCsClosure()!.UpValues[0].Read<LuaCoroutine>();
             var stack = context.Thread.Stack;
             var frameBase = stack.Count;
 
@@ -68,7 +71,7 @@ public sealed class CoroutineLibrary
             {
                 Base = frameBase,
                 VariableArgumentCount = 0,
-                Function = arg0,
+                Function = thread.Function,
             });
             try
             {

+ 46 - 18
src/Lua/Standard/DebugLibrary.cs

@@ -184,20 +184,35 @@ public class DebugLibrary
         var index = context.GetArgument<int>(1) - 1;
         if (func is not Closure closure)
         {
+            if (func is CsClosure csClosure)
+            {
+                var upValues = csClosure.UpValues;
+                if (index < 0 || index >= upValues.Length)
+                {
+                    return new(0);
+                }
+
+                buffer.Span[0] = "";
+                buffer.Span[1] = upValues[index];
+                return new(1);
+            }
+
             return new(0);
         }
 
-        var upValues = closure.UpValues;
-        var descriptions = closure.Proto.UpValues;
-        if (index < 0 || index >= descriptions.Length)
         {
-            return new(0);
-        }
+            var upValues = closure.UpValues;
+            var descriptions = closure.Proto.UpValues;
+            if (index < 0 || index >= descriptions.Length)
+            {
+                return new(0);
+            }
 
-        var description = descriptions[index];
-        buffer.Span[0] = description.Name.ToString();
-        buffer.Span[1] = upValues[index].GetValue();
-        return new(2);
+            var description = descriptions[index];
+            buffer.Span[0] = description.Name.ToString();
+            buffer.Span[1] = upValues[index].GetValue();
+            return new(2);
+        }
     }
 
     public ValueTask<int> SetUpValue(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
@@ -207,20 +222,33 @@ public class DebugLibrary
         var value = context.GetArgument(2);
         if (func is not Closure closure)
         {
+            if (func is CsClosure csClosure)
+            {
+                var upValues = csClosure.UpValues;
+                if (index < 0 || index >= upValues.Length)
+                {
+                    upValues[index - 1] = value;
+                    buffer.Span[0] = "";
+                    return new(0);
+                }
+            }
+
             return new(0);
         }
 
-        var upValues = closure.UpValues;
-        var descriptions = closure.Proto.UpValues;
-        if (index < 0 || index >= descriptions.Length)
         {
-            return new(0);
-        }
+            var upValues = closure.UpValues;
+            var descriptions = closure.Proto.UpValues;
+            if (index < 0 || index >= descriptions.Length)
+            {
+                return new(0);
+            }
 
-        var description = descriptions[index];
-        buffer.Span[0] = description.Name.ToString();
-        upValues[index].SetValue(value);
-        return new(1);
+            var description = descriptions[index];
+            buffer.Span[0] = description.Name.ToString();
+            upValues[index].SetValue(value);
+            return new(1);
+        }
     }
 
     public ValueTask<int> GetMetatable(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)

+ 4 - 3
src/Lua/Standard/FileHandle.cs

@@ -176,11 +176,12 @@ public class FileHandle : ILuaUserData
             ? context.Arguments[1]
             : "*l";
 
-        LuaValue[] formats = [format];
 
-        buffer.Span[0] = new LuaFunction("iterator", (context, buffer, cancellationToken) =>
+        buffer.Span[0] = new CsClosure("iterator", [new (file),format],static (context, buffer, cancellationToken) =>
         {
-            var resultCount = IOHelper.Read(context.State, file, "lines", 0, formats, buffer, true);
+            var upValues = context.GetCsClosure()!.UpValues.AsSpan();
+            var file = upValues[0].Read<FileHandle>();
+            var resultCount = IOHelper.Read(context.State, file, "lines", 0, upValues[1..], buffer, true);
             return new(resultCount);
         });
 

+ 10 - 3
src/Lua/Standard/IOLibrary.cs

@@ -1,4 +1,5 @@
 using Lua.Internal;
+using Lua.Runtime;
 using Lua.Standard.Internal;
 
 namespace Lua.Standard;
@@ -96,8 +97,9 @@ public sealed class IOLibrary
         if (context.ArgumentCount == 0)
         {
             var file = context.State.Environment["io"].Read<LuaTable>()["stdio"].Read<FileHandle>();
-            buffer.Span[0] = new LuaFunction("iterator", (context, buffer, ct) =>
+            buffer.Span[0] = new CsClosure("iterator",[new (file)] ,static (context, buffer, ct) =>
             {
+                var file = context.GetCsClosure()!.UpValues[0].Read<FileHandle>();
                 var resultCount = IOHelper.Read(context.State, file, "lines", 0, [], buffer, true);
                 if (resultCount > 0 && buffer.Span[0].Type is LuaValueType.Nil)
                 {
@@ -115,10 +117,15 @@ public sealed class IOLibrary
             IOHelper.Open(context.State, fileName, "r", methodBuffer.AsMemory(), true);
 
             var file = methodBuffer[0].Read<FileHandle>();
-            var formats = context.Arguments[1..].ToArray();
+            var upValues = new LuaValue[context.Arguments.Length];
+            upValues[0] = new(file);
+            context.Arguments[1..].CopyTo(upValues[1..]);
 
-            buffer.Span[0] = new LuaFunction("iterator", (context, buffer, ct) =>
+            buffer.Span[0] = new CsClosure("iterator", upValues, static (context, buffer, ct) =>
             {
+                var upValues = context.GetCsClosure()!.UpValues;
+                var file = upValues[0].Read<FileHandle>();
+                var formats = upValues.AsSpan(1);
                 var resultCount = IOHelper.Read(context.State, file, "lines", 0, formats, buffer, true);
                 if (resultCount > 0 && buffer.Span[0].Type is LuaValueType.Nil)
                 {

+ 7 - 3
src/Lua/Standard/StringLibrary.cs

@@ -1,5 +1,7 @@
 using System.Text;
+using System.Text.RegularExpressions;
 using Lua.Internal;
+using Lua.Runtime;
 
 namespace Lua.Standard;
 
@@ -429,17 +431,19 @@ public sealed class StringLibrary
 
         var regex = StringHelper.ToRegex(pattern);
         var matches = regex.Matches(s);
-        var i = 0;
 
-        buffer.Span[0] = new LuaFunction("iterator", (context, buffer, cancellationToken) =>
+        buffer.Span[0] = new CsClosure("iterator",[new LuaValue(matches),0],static (context, buffer, cancellationToken) =>
         {
+            var upValues = context.GetCsClosure()!.UpValues;
+            var matches = upValues[0].Read<MatchCollection>();
+            var i = upValues[1].Read<int>();
             if (matches.Count > i)
             {
                 var match = matches[i];
                 var groups = match.Groups;
 
                 i++;
-
+                 upValues[1] = i;
                 if (groups.Count == 1)
                 {
                     buffer.Span[0] = match.Value;