Browse Source

Add: dofile, load, loadfile

AnnulusGames 1 year ago
parent
commit
444b8ca6ea

+ 5 - 0
src/Lua/CodeAnalysis/Compilation/LuaCompiler.cs

@@ -9,6 +9,11 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
 {
 {
     public static readonly LuaCompiler Default = new();
     public static readonly LuaCompiler Default = new();
 
 
+    public Chunk Compile(string source, string? chunkName = null)
+    {
+        return Compile(LuaSyntaxTree.Parse(source, chunkName), chunkName);
+    }
+
     /// <summary>
     /// <summary>
     /// Returns a compiled chunk of the syntax tree.
     /// Returns a compiled chunk of the syntax tree.
     /// </summary>
     /// </summary>

+ 2 - 2
src/Lua/LuaFunctionExecutionContext.cs

@@ -39,11 +39,11 @@ public readonly record struct LuaFunctionExecutionContext
             var thread = State.CurrentThread;
             var thread = State.CurrentThread;
             if (LuaValue.TryGetLuaValueType(typeof(T), out var type))
             if (LuaValue.TryGetLuaValueType(typeof(T), out var type))
             {
             {
-                LuaRuntimeException.BadArgument(State.GetTracebacks(), 1, thread.GetCurrentFrame().Function.Name, type.ToString(), arg.Type.ToString());
+                LuaRuntimeException.BadArgument(State.GetTracebacks(), index + 1, thread.GetCurrentFrame().Function.Name, type.ToString(), arg.Type.ToString());
             }
             }
             else
             else
             {
             {
-                LuaRuntimeException.BadArgument(State.GetTracebacks(), 1, thread.GetCurrentFrame().Function.Name, typeof(T).Name, arg.Type.ToString());
+                LuaRuntimeException.BadArgument(State.GetTracebacks(), index + 1, thread.GetCurrentFrame().Function.Name, typeof(T).Name, arg.Type.ToString());
             }
             }
         }
         }
 
 

+ 5 - 5
src/Lua/Runtime/Closure.cs

@@ -7,7 +7,7 @@ public sealed class Closure : LuaFunction
     Chunk proto;
     Chunk proto;
     FastListCore<UpValue> upValues;
     FastListCore<UpValue> upValues;
 
 
-    public Closure(LuaState state, Chunk proto)
+    public Closure(LuaState state, Chunk proto, LuaTable? environment = null)
     {
     {
         this.proto = proto;
         this.proto = proto;
 
 
@@ -15,7 +15,7 @@ public sealed class Closure : LuaFunction
         for (int i = 0; i < proto.UpValues.Length; i++)
         for (int i = 0; i < proto.UpValues.Length; i++)
         {
         {
             var description = proto.UpValues[i];
             var description = proto.UpValues[i];
-            var upValue = GetUpValueFromDescription(state, proto, description);
+            var upValue = GetUpValueFromDescription(state, environment == null ? state.EnvUpValue : UpValue.Closed(state.CurrentThread, environment), proto, description);
             upValues.Add(upValue);
             upValues.Add(upValue);
         }
         }
     }
     }
@@ -30,7 +30,7 @@ public sealed class Closure : LuaFunction
         return LuaVirtualMachine.ExecuteClosureAsync(context.State, this, context.State.CurrentThread.GetCurrentFrame(), buffer, cancellationToken);
         return LuaVirtualMachine.ExecuteClosureAsync(context.State, this, context.State.CurrentThread.GetCurrentFrame(), buffer, cancellationToken);
     }
     }
 
 
-    static UpValue GetUpValueFromDescription(LuaState state, Chunk proto, UpValueInfo description)
+    static UpValue GetUpValueFromDescription(LuaState state, UpValue envUpValue, Chunk proto, UpValueInfo description)
     {
     {
         if (description.IsInRegister)
         if (description.IsInRegister)
         {
         {
@@ -39,11 +39,11 @@ public sealed class Closure : LuaFunction
         }
         }
         else if (description.Index == -1) // -1 is global environment
         else if (description.Index == -1) // -1 is global environment
         {
         {
-            return state.EnvUpValue;
+            return envUpValue;
         }
         }
         else
         else
         {
         {
-            return GetUpValueFromDescription(state, proto.Parent!, proto.Parent!.UpValues[description.Index]);
+            return GetUpValueFromDescription(state, envUpValue, proto.Parent!, proto.Parent!.UpValues[description.Index]);
         }
         }
     }
     }
 }
 }

+ 22 - 0
src/Lua/Standard/Basic/DoFileFunction.cs

@@ -0,0 +1,22 @@
+using Lua.CodeAnalysis.Compilation;
+using Lua.Runtime;
+
+namespace Lua.Standard.Basic;
+
+public sealed class DoFileFunction : LuaFunction
+{
+    public override string Name => "dofile";
+    public static readonly DoFileFunction Instance = new();
+
+    protected override async ValueTask<int> InvokeAsyncCore(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    {
+        var arg0 = context.ReadArgument<string>(0);
+
+        // do not use LuaState.DoFileAsync as it uses the new LuaFunctionExecutionContext
+        var text = await File.ReadAllTextAsync(arg0, cancellationToken);
+        var fileName = Path.GetFileName(arg0);
+        var chunk = LuaCompiler.Default.Compile(text, fileName);
+
+        return await new Closure(context.State, chunk).InvokeAsync(context, buffer, cancellationToken);
+    }
+}

+ 35 - 0
src/Lua/Standard/Basic/LoadFileFunction.cs

@@ -0,0 +1,35 @@
+using Lua.CodeAnalysis.Compilation;
+using Lua.Runtime;
+
+namespace Lua.Standard.Basic;
+
+public sealed class LoadFileFunction : LuaFunction
+{
+    public override string Name => "loadfile";
+    public static readonly LoadFileFunction Instance = new();
+
+    protected override async ValueTask<int> InvokeAsyncCore(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    {
+        // Lua-CSharp does not support binary chunks, the mode argument is ignored.
+        var arg0 = context.ReadArgument<string>(0);
+        var arg2 = context.ArgumentCount >= 3
+            ? context.ReadArgument<LuaTable>(2)
+            : null;
+
+        // do not use LuaState.DoFileAsync as it uses the new LuaFunctionExecutionContext
+        try
+        {
+            var text = await File.ReadAllTextAsync(arg0, cancellationToken);
+            var fileName = Path.GetFileName(arg0);
+            var chunk = LuaCompiler.Default.Compile(text, fileName);
+            buffer.Span[0] = new Closure(context.State, chunk, arg2);
+            return 1;
+        }
+        catch (Exception ex)
+        {
+            buffer.Span[0] = LuaValue.Nil;
+            buffer.Span[1] = ex.Message;
+            return 2;
+        }
+    }
+}

+ 51 - 0
src/Lua/Standard/Basic/LoadFunction.cs

@@ -0,0 +1,51 @@
+using Lua.CodeAnalysis.Compilation;
+using Lua.Runtime;
+
+namespace Lua.Standard.Basic;
+
+public sealed class LoadFunction : LuaFunction
+{
+    public override string Name => "load";
+    public static readonly LoadFunction Instance = new();
+
+    protected override ValueTask<int> InvokeAsyncCore(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    {
+        // Lua-CSharp does not support binary chunks, the mode argument is ignored.
+        var arg0 = context.ReadArgument(0);
+
+        var arg1 = context.ArgumentCount >= 2
+            ? context.ReadArgument<string>(1)
+            : null;
+
+        var arg3 = context.ArgumentCount >= 4
+            ? context.ReadArgument<LuaTable>(3)
+            : null;
+
+        // do not use LuaState.DoFileAsync as it uses the new LuaFunctionExecutionContext
+        try
+        {
+            if (arg0.TryRead<string>(out var str))
+            {
+                var chunk = LuaCompiler.Default.Compile(str, arg1 ?? "chunk");
+                buffer.Span[0] = new Closure(context.State, chunk, arg3);
+                return new(1);
+            }
+            else if (arg0.TryRead<LuaFunction>(out var function))
+            {
+                // TODO: 
+                throw new NotImplementedException();
+            }
+            else
+            {
+                LuaRuntimeException.BadArgument(context.State.GetTracebacks(), 1, Name);
+                return default; // dummy
+            }
+        }
+        catch (Exception ex)
+        {
+            buffer.Span[0] = LuaValue.Nil;
+            buffer.Span[1] = ex.Message;
+            return new(2);
+        }
+    }
+}