Closure.cs 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. using System.Runtime.CompilerServices;
  2. using Lua.Internal;
  3. namespace Lua.Runtime;
  4. public sealed class Closure : LuaFunction
  5. {
  6. Chunk proto;
  7. FastListCore<UpValue> upValues;
  8. public Closure(LuaState state, Chunk proto, LuaTable? environment = null)
  9. : base(proto.Name, (context, buffer, ct) => LuaVirtualMachine.ExecuteClosureAsync(context.State, buffer, ct))
  10. {
  11. this.proto = proto;
  12. // add upvalues
  13. for (int i = 0; i < proto.UpValues.Length; i++)
  14. {
  15. var description = proto.UpValues[i];
  16. var upValue = GetUpValueFromDescription(state, state.CurrentThread, environment == null ? state.EnvUpValue : UpValue.Closed(environment), description);
  17. upValues.Add(upValue);
  18. }
  19. IsClosure = true;
  20. }
  21. public Chunk Proto => proto;
  22. public ReadOnlySpan<UpValue> UpValues => upValues.AsSpan();
  23. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  24. internal LuaValue GetUpValue(int index)
  25. {
  26. return upValues[index].GetValue();
  27. }
  28. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  29. internal void SetUpValue(int index, LuaValue value)
  30. {
  31. upValues[index].SetValue(value);
  32. }
  33. static UpValue GetUpValueFromDescription(LuaState state, LuaThread thread, UpValue envUpValue, UpValueInfo description)
  34. {
  35. if (description.IsInRegister)
  36. {
  37. return state.GetOrAddUpValue(thread, thread.GetCallStackFrames()[^1].Base + description.Index);
  38. }
  39. if (description.Index == -1) // -1 is global environment
  40. {
  41. return envUpValue;
  42. }
  43. {
  44. if (thread.GetCallStackFrames()[^1].Function is Closure parentClosure)
  45. {
  46. return parentClosure.UpValues[description.Index];
  47. }
  48. throw new InvalidOperationException("invalid upvalue description.");
  49. }
  50. }
  51. }