Closure.cs 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  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. }
  20. public Chunk Proto => proto;
  21. public ReadOnlySpan<UpValue> UpValues => upValues.AsSpan();
  22. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  23. internal LuaValue GetUpValue(int index)
  24. {
  25. return upValues[index].GetValue();
  26. }
  27. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  28. internal void SetUpValue(int index, LuaValue value)
  29. {
  30. upValues[index].SetValue(value);
  31. }
  32. static UpValue GetUpValueFromDescription(LuaState state, LuaThread thread, UpValue envUpValue, UpValueInfo description)
  33. {
  34. if (description.IsInRegister)
  35. {
  36. return state.GetOrAddUpValue(thread, thread.GetCallStackFrames()[^1].Base + description.Index);
  37. }
  38. if (description.Index == -1) // -1 is global environment
  39. {
  40. return envUpValue;
  41. }
  42. if (thread.GetCallStackFrames()[^1].Function is Closure parentClosure)
  43. {
  44. return parentClosure.UpValues[description.Index];
  45. }
  46. throw new Exception();
  47. }
  48. }