Browse Source

Add: ipairs

AnnulusGames 1 year ago
parent
commit
46bb33a454
2 changed files with 51 additions and 0 deletions
  1. 1 0
      src/Lua/Runtime/Metamethods.cs
  2. 50 0
      src/Lua/Standard/Basic/IPairsFunction.cs

+ 1 - 0
src/Lua/Runtime/Metamethods.cs

@@ -18,5 +18,6 @@ public static class Metamethods
     public const string Le = "__le";
     public const string Call = "__call";
     public const string Concat = "__concat";
+    public const string IPairs = "__ipairs";
     public new const string ToString = "__tostring";
 }

+ 50 - 0
src/Lua/Standard/Basic/IPairsFunction.cs

@@ -0,0 +1,50 @@
+using Lua.Runtime;
+
+namespace Lua.Standard.Basic;
+
+public sealed class IPairsFunction : LuaFunction
+{
+    public override string Name => "ipairs";
+    public static readonly IPairsFunction Instance = new();
+
+    protected override ValueTask<int> InvokeAsyncCore(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    {
+        var arg0 = context.ReadArgument<LuaTable>(0);
+
+        // If table has a metamethod __ipairs, calls it with table as argument and returns the first three results from the call.
+        if (arg0.Metatable != null && arg0.Metatable.TryGetValue(Metamethods.IPairs, out var metamethod))
+        {
+            if (!metamethod.TryRead<LuaFunction>(out var function))
+            {
+                LuaRuntimeException.AttemptInvalidOperation(context.State.GetTracebacks(), "call", metamethod);
+            }
+
+            return function.InvokeAsync(context, buffer, cancellationToken);
+        }
+
+        buffer.Span[0] = new Iterator(arg0);
+        return new(1);
+    }
+
+    class Iterator(LuaTable table) : LuaFunction
+    {
+        int i;
+
+        protected override ValueTask<int> InvokeAsyncCore(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+        {
+            i++;
+            if (table.TryGetValue(i, out var value))
+            {
+                buffer.Span[0] = i;
+                buffer.Span[1] = value;
+            }
+            else
+            {
+                buffer.Span[0] = LuaValue.Nil;
+                buffer.Span[1] = LuaValue.Nil;
+            }
+
+            return new(2);
+        }
+    }
+}