-
Notifications
You must be signed in to change notification settings - Fork 45
enable pairs/ipairs and next for ILuaUserData #207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v0.5-dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -136,10 +136,20 @@ public ValueTask<int> GetMetatable(LuaFunctionExecutionContext context, Cancella | |
|
|
||
| public async ValueTask<int> IPairs(LuaFunctionExecutionContext context, CancellationToken cancellationToken) | ||
| { | ||
| var arg0 = context.GetArgument<LuaTable>(0); | ||
| var arg0 = context.GetArgument(0); | ||
|
|
||
| LuaTable metatable = default; | ||
| if (arg0.TryRead(out LuaTable table)) | ||
| { | ||
| metatable = table.Metatable; | ||
| } | ||
| else if (arg0.TryRead(out ILuaUserData userdata)) | ||
| { | ||
| metatable = userdata.Metatable; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead, use LuaState.TryGetMetatable. |
||
| } | ||
|
|
||
| // 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 (metatable != null && metatable.TryGetValue(Metamethods.IPairs, out var metamethod)) | ||
| { | ||
| var stack = context.Thread.Stack; | ||
| var top = stack.Count; | ||
|
|
@@ -218,10 +228,16 @@ public ValueTask<int> Load(LuaFunctionExecutionContext context, CancellationToke | |
|
|
||
| public ValueTask<int> Next(LuaFunctionExecutionContext context, CancellationToken cancellationToken) | ||
| { | ||
| var arg0 = context.GetArgument<LuaTable>(0); | ||
| var arg0 = context.GetArgument(0); | ||
| var arg1 = context.HasArgument(1) ? context.Arguments[1] : LuaValue.Nil; | ||
|
|
||
| if (arg0.TryGetNext(arg1, out var kv)) | ||
| ILuaEnumerable enumerable = default; | ||
| if (arg0.TryRead(out LuaTable table)) | ||
| enumerable = table; | ||
| else if (arg0.TryRead(out ILuaUserData userdata) && userdata is ILuaEnumerable) | ||
| enumerable = userdata as ILuaEnumerable; | ||
|
|
||
| if (enumerable != null && enumerable.TryGetNext(arg1, out var kv)) | ||
| { | ||
| return new(context.Return(kv.Key, kv.Value)); | ||
| } | ||
|
|
@@ -233,10 +249,20 @@ public ValueTask<int> Next(LuaFunctionExecutionContext context, CancellationToke | |
|
|
||
| public async ValueTask<int> Pairs(LuaFunctionExecutionContext context, CancellationToken cancellationToken) | ||
| { | ||
| var arg0 = context.GetArgument<LuaTable>(0); | ||
| var arg0 = context.GetArgument(0); | ||
|
|
||
| LuaTable metatable = default; | ||
| if (arg0.TryRead(out LuaTable table)) | ||
| { | ||
| metatable = table.Metatable; | ||
| } | ||
| else if (arg0.TryRead(out ILuaUserData userdata)) | ||
| { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead, use LuaState.TryGetMetatable. |
||
| metatable = userdata.Metatable; | ||
| } | ||
|
|
||
| // If table has a metamethod __pairs, calls it with table as argument and returns the first three results from the call. | ||
| if (arg0.Metatable != null && arg0.Metatable.TryGetValue(Metamethods.Pairs, out var metamethod)) | ||
| if (metatable != null && metatable.TryGetValue(Metamethods.Pairs, out var metamethod)) | ||
| { | ||
| var stack = context.Thread.Stack; | ||
| var top = stack.Count; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| // Copyright (C) 2021-2025 Steffen Itterheim | ||
| // Refer to included LICENSE file for terms and conditions. | ||
|
Comment on lines
+1
to
+2
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not your repository.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry about that, it's an automation in my IDE that adds these |
||
|
|
||
| using Lua.Runtime; | ||
| using Lua.Standard; | ||
| using Lua.Tests.Helpers; | ||
|
|
||
| namespace Lua.Tests.UserDataPairs; | ||
|
|
||
| public class UserDataPairsTests | ||
| { | ||
| [TestCase("userdatapairs.lua")] | ||
| public async Task Test_UserDataPairs(string file) | ||
| { | ||
| var state = LuaState.Create(); | ||
| state.Platform.StandardIO = new TestStandardIO(); | ||
| state.OpenStandardLibraries(); | ||
| state.Environment["LuaList"] = new LuaValue(new LuaList<int>()); | ||
|
|
||
| var path = FileHelper.GetAbsolutePath(file); | ||
| Directory.SetCurrentDirectory(Path.GetDirectoryName(path)!); | ||
| try | ||
| { | ||
| await state.DoFileAsync(Path.GetFileName(file)); | ||
| } | ||
| catch (LuaRuntimeException e) | ||
| { | ||
| var luaTraceback = e.LuaTraceback; | ||
| if (luaTraceback == null) | ||
| { | ||
| throw; | ||
| } | ||
|
|
||
| var line = luaTraceback.FirstLine; | ||
| throw new($"{path}:{line} \n{e.InnerException}\n {e}"); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| public sealed class LuaList<T> : ILuaUserData, ILuaEnumerable | ||
| { | ||
| static readonly LuaFunction __len = new(Metamethods.Len, (context, _) => | ||
| { | ||
| return new ValueTask<int>(context.Return(3)); | ||
| }); | ||
| static readonly LuaFunction __pairs = new(Metamethods.Pairs, (context, _) => | ||
| { | ||
| var arg0 = context.GetArgument(0); | ||
| return new ValueTask<int>(context.Return(LuaListIterator, arg0, LuaValue.Nil)); | ||
| }); | ||
|
|
||
| static readonly LuaFunction LuaListIterator = new LuaFunction("listnext", (context, token) => | ||
| { | ||
| var list = context.GetArgument<LuaList<T>>(0); | ||
| var key = context.HasArgument(1) ? context.Arguments[1] : LuaValue.Nil; | ||
|
|
||
| var index = -1; | ||
| if (key.Type is LuaValueType.Nil) | ||
| { | ||
| index = 0; | ||
| } | ||
| else if (key.TryRead(out int number) && number > 0 && number < list.ManagedArray.Length) | ||
| { | ||
| index = number; | ||
| } | ||
|
|
||
| if (index != -1) | ||
| { | ||
| return new(context.Return(++index, list.ManagedArray[index - 1])); | ||
| } | ||
|
|
||
| return new(context.Return(LuaValue.Nil)); | ||
| }); | ||
|
|
||
| static LuaTable s_Metatable; | ||
| public LuaTable Metatable { get => s_Metatable; set => throw new NotImplementedException(); } | ||
|
|
||
| public int[] ManagedArray { get; } | ||
| //public Dictionary<string, bool> ManagedDict { get; } | ||
| public LuaList() | ||
| { | ||
| ManagedArray = new [] { 1,2,3,4,5 }; | ||
| //ManagedDict = new Dictionary<string, bool> {{"TRUE", true}, {"FALSE", false}}; | ||
|
|
||
| s_Metatable = new LuaTable(); | ||
| s_Metatable[Metamethods.Len] = __len; | ||
| s_Metatable[Metamethods.Pairs] = __pairs; | ||
| s_Metatable[Metamethods.IPairs] = __pairs; | ||
| } | ||
|
|
||
| public bool TryGetNext(LuaValue key, out KeyValuePair<LuaValue, LuaValue> pair) | ||
| { | ||
| var index = -1; | ||
| if (key.Type is LuaValueType.Nil) | ||
| { | ||
| index = 0; | ||
| } | ||
| else if (key.TryRead(out int integer) && integer > 0 && integer <= ManagedArray.Length) | ||
| { | ||
| index = integer; | ||
| } | ||
|
|
||
| if (index != -1) | ||
| { | ||
| var span = ManagedArray.AsSpan(index); | ||
| for (var i = 0; i < span.Length; i++) | ||
| { | ||
| pair = new(index + i + 1, span[i]); | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| pair = default; | ||
| return false; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| local iterations = 0 | ||
|
|
||
| print("LuaList pairs:") | ||
| for k, v in pairs(LuaList) do | ||
| print("List[" .. tostring(k) .. "] = " .. tostring(v)) | ||
| assert(k == v) | ||
| iterations = iterations + 1 | ||
| end | ||
| assert(iterations == 5) | ||
|
|
||
|
|
||
| iterations = 0 | ||
| print("LuaList ipairs:") | ||
| for i, v in ipairs(LuaList) do | ||
| print("List[" .. tostring(i) .. "] = " .. tostring(v)) | ||
| assert(i == v) | ||
| iterations = iterations + 1 | ||
| end | ||
| assert(iterations == 5) | ||
|
|
||
|
|
||
| iterations = 0 | ||
| print("LuaList next:") | ||
| local i, v = next(LuaList, nil) | ||
| while i do | ||
| print("List[" .. tostring(i) .. "] = " .. tostring(v)) | ||
| assert(i == v) | ||
| iterations = iterations + 1 | ||
|
|
||
| i, v = next(LuaList, i) | ||
| end | ||
| assert(iterations == 5) | ||
|
|
||
|
|
||
| local t = | ||
| { | ||
| 1, 2, 3, 4, 5, | ||
| ["some key"] = "some value", | ||
| ["another key"] = "another value", | ||
| [-1000] = -1001, | ||
| [_G] = print, | ||
| } | ||
|
|
||
| print("LuaTable pairs:") | ||
| for k, v in pairs(t) do | ||
| print(k, v) | ||
| end | ||
| print("LuaTable ipairs:") | ||
| for i, v in ipairs(t) do | ||
| print(i, v) | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate files for this interface.