LuaState.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. using Lua.Internal;
  2. using Lua.Runtime;
  3. namespace Lua;
  4. public sealed class LuaState
  5. {
  6. public const string DefaultChunkName = "chunk";
  7. readonly LuaMainThread mainThread = new();
  8. FastListCore<UpValue> openUpValues;
  9. FastStackCore<LuaThread> threadStack;
  10. readonly LuaTable environment;
  11. readonly UpValue envUpValue;
  12. bool isRunning;
  13. internal UpValue EnvUpValue => envUpValue;
  14. internal ref FastStackCore<LuaThread> ThreadStack => ref threadStack;
  15. internal ref FastListCore<UpValue> OpenUpValues => ref openUpValues;
  16. public LuaTable Environment => environment;
  17. public LuaMainThread MainThread => mainThread;
  18. public LuaThread CurrentThread
  19. {
  20. get
  21. {
  22. if (threadStack.TryPeek(out var thread)) return thread;
  23. return mainThread;
  24. }
  25. }
  26. public static LuaState Create()
  27. {
  28. return new();
  29. }
  30. LuaState()
  31. {
  32. environment = new();
  33. envUpValue = UpValue.Closed(mainThread, environment);
  34. }
  35. public async ValueTask<int> RunAsync(Chunk chunk, Memory<LuaValue> buffer, CancellationToken cancellationToken = default)
  36. {
  37. ThrowIfRunning();
  38. Volatile.Write(ref isRunning, true);
  39. try
  40. {
  41. var closure = new Closure(this, chunk);
  42. return await closure.InvokeAsync(new()
  43. {
  44. State = this,
  45. ArgumentCount = 0,
  46. StackPosition = 0,
  47. SourcePosition = null,
  48. RootChunkName = chunk.Name ?? DefaultChunkName,
  49. ChunkName = chunk.Name ?? DefaultChunkName,
  50. }, buffer, cancellationToken);
  51. }
  52. finally
  53. {
  54. Volatile.Write(ref isRunning, false);
  55. }
  56. }
  57. public void Push(LuaValue value)
  58. {
  59. CurrentThread.Stack.Push(value);
  60. }
  61. public LuaThread CreateThread(LuaFunction function, bool isProtectedMode = true)
  62. {
  63. return new LuaCoroutine(this, function, isProtectedMode);
  64. }
  65. public Tracebacks GetTracebacks()
  66. {
  67. return MainThread.GetTracebacks();
  68. }
  69. internal UpValue GetOrAddUpValue(LuaThread thread, int registerIndex)
  70. {
  71. foreach (var upValue in openUpValues.AsSpan())
  72. {
  73. if (upValue.RegisterIndex == registerIndex && upValue.Thread == thread)
  74. {
  75. return upValue;
  76. }
  77. }
  78. var newUpValue = UpValue.Open(thread, registerIndex);
  79. openUpValues.Add(newUpValue);
  80. return newUpValue;
  81. }
  82. internal void CloseUpValues(LuaThread thread, int frameBase)
  83. {
  84. for (int i = 0; i < openUpValues.Length; i++)
  85. {
  86. var upValue = openUpValues[i];
  87. if (upValue.Thread != thread) continue;
  88. if (upValue.RegisterIndex >= frameBase)
  89. {
  90. upValue.Close();
  91. openUpValues.RemoveAtSwapback(i);
  92. i--;
  93. }
  94. }
  95. }
  96. void ThrowIfRunning()
  97. {
  98. if (Volatile.Read(ref isRunning))
  99. {
  100. throw new InvalidOperationException("the lua state is currently running");
  101. }
  102. }
  103. }