Browse Source

Add: require

AnnulusGames 1 year ago
parent
commit
6d2b8f9d78

+ 1 - 1
src/Lua/ILuaModuleLoader.cs

@@ -3,5 +3,5 @@ namespace Lua;
 public interface ILuaModuleLoader
 {
     bool Exists(string moduleName);
-    ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default);
+    ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default);
 }

+ 6 - 6
src/Lua/Loaders/CompositeModuleLoader.cs

@@ -11,7 +11,7 @@ public static class CompositeModuleLoader
                 loader1.Exists(moduleName);
         }
 
-        public ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
+        public ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
         {
             if (loader0.Exists(moduleName))
             {
@@ -36,7 +36,7 @@ public static class CompositeModuleLoader
                 loader2.Exists(moduleName);
         }
 
-        public ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
+        public ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
         {
             if (loader0.Exists(moduleName))
             {
@@ -67,7 +67,7 @@ public static class CompositeModuleLoader
                 loader3.Exists(moduleName);
         }
 
-        public ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
+        public ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
         {
             if (loader0.Exists(moduleName))
             {
@@ -104,7 +104,7 @@ public static class CompositeModuleLoader
                 loader4.Exists(moduleName);
         }
 
-        public ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
+        public ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
         {
             if (loader0.Exists(moduleName))
             {
@@ -147,7 +147,7 @@ public static class CompositeModuleLoader
                 loader5.Exists(moduleName);
         }
 
-        public ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
+        public ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
         {
             if (loader0.Exists(moduleName))
             {
@@ -196,7 +196,7 @@ public static class CompositeModuleLoader
             return false;
         }
 
-        public ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
+        public ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
         {
             foreach (var loader in loaders)
             {

+ 5 - 2
src/Lua/Loaders/FileModuleLoader.cs

@@ -10,8 +10,11 @@ public sealed class FileModuleLoader : ILuaModuleLoader
         return File.Exists(moduleName);
     }
 
-    public async ValueTask<LuaValue> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
+    public async ValueTask<LuaModule> LoadAsync(string moduleName, CancellationToken cancellationToken = default)
     {
-        return await File.ReadAllTextAsync(moduleName, cancellationToken);
+        var path = moduleName;
+        if (!Path.HasExtension(path)) path += ".lua";
+        var text = await File.ReadAllTextAsync(path, cancellationToken);
+        return new LuaModule(moduleName, text);
     }
 }

+ 29 - 0
src/Lua/LuaModule.cs

@@ -0,0 +1,29 @@
+namespace Lua;
+
+public enum LuaModuleType
+{
+    Text,
+}
+
+public readonly struct LuaModule
+{
+    public string Name => name;
+    public LuaModuleType Type => type;
+
+    readonly string name;
+    readonly LuaModuleType type;
+    readonly object referenceValue;
+
+    public LuaModule(string name, string text)
+    {
+        this.name = name;
+        type = LuaModuleType.Text;
+        referenceValue = text;
+    }
+
+    public string ReadText()
+    {
+        if (type != LuaModuleType.Text) throw new Exception(); // TODO: add message
+        return (string)referenceValue;
+    }
+}

+ 33 - 0
src/Lua/Standard/Modules/RequireFunction.cs

@@ -0,0 +1,33 @@
+
+using Lua.CodeAnalysis.Compilation;
+using Lua.Internal;
+using Lua.Runtime;
+
+namespace Lua.Standard.Modules;
+
+public sealed class RequireFunction : LuaFunction
+{
+    public override string Name => "require";
+    public static readonly RequireFunction Instance = new();
+
+    protected override async ValueTask<int> InvokeAsyncCore(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
+    {
+        var arg0 = context.ReadArgument<string>(0);
+        var loaded = context.State.Environment["package"].Read<LuaTable>()["loaded"].Read<LuaTable>();
+
+        if (!loaded.TryGetValue(arg0, out var loadedTable))
+        {
+            var module = await context.State.ModuleLoader.LoadAsync(arg0, cancellationToken);
+            var chunk = LuaCompiler.Default.Compile(module.ReadText(), module.Name);
+
+            using var methodBuffer = new PooledArray<LuaValue>(1);
+            await new Closure(context.State, chunk).InvokeAsync(context, methodBuffer.AsMemory(), cancellationToken);
+
+            loadedTable = methodBuffer[0];
+            loaded[arg0] = loadedTable;
+        }
+
+        buffer.Span[0] = loadedTable;
+        return 1;
+    }
+}

+ 10 - 0
src/Lua/Standard/OpenLibExtensions.cs

@@ -1,6 +1,7 @@
 using Lua.Standard.Basic;
 using Lua.Standard.Coroutines;
 using Lua.Standard.Mathematics;
+using Lua.Standard.Modules;
 
 namespace Lua.Standard;
 
@@ -97,4 +98,13 @@ public static class OpenLibExtensions
 
         state.Environment["math"] = table;
     }
+
+    public static void OpenModuleLibrary(this LuaState state)
+    {
+        var package = new LuaTable(0, 1);
+        package["loaded"] = new LuaTable();
+        state.Environment["package"] = package;
+        
+        state.Environment[RequireFunction.Instance.Name] = RequireFunction.Instance;
+    }
 }