LuaState.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using Lua.CodeAnalysis.Compilation;
  2. using System.Diagnostics.CodeAnalysis;
  3. using System.Runtime.CompilerServices;
  4. using Lua.Internal;
  5. using Lua.Loaders;
  6. using Lua.Runtime;
  7. using System.Buffers;
  8. using System.Text;
  9. namespace Lua;
  10. public sealed class LuaState
  11. {
  12. // states
  13. readonly LuaMainThread mainThread;
  14. FastListCore<UpValue> openUpValues;
  15. FastStackCore<LuaThread> threadStack;
  16. readonly LuaTable packages = new();
  17. readonly LuaTable environment;
  18. readonly LuaTable registry = new();
  19. readonly UpValue envUpValue;
  20. FastStackCore<LuaDebug.LuaDebugBuffer> debugBufferPool;
  21. internal int CallCount;
  22. internal UpValue EnvUpValue => envUpValue;
  23. internal ref FastStackCore<LuaThread> ThreadStack => ref threadStack;
  24. internal ref FastListCore<UpValue> OpenUpValues => ref openUpValues;
  25. internal ref FastStackCore<LuaDebug.LuaDebugBuffer> DebugBufferPool => ref debugBufferPool;
  26. public LuaTable Environment => environment;
  27. public LuaTable Registry => registry;
  28. public LuaTable LoadedModules => packages;
  29. public LuaMainThread MainThread => mainThread;
  30. public ILuaModuleLoader ModuleLoader { get; set; } = FileModuleLoader.Instance;
  31. // metatables
  32. LuaTable? nilMetatable;
  33. LuaTable? numberMetatable;
  34. LuaTable? stringMetatable;
  35. LuaTable? booleanMetatable;
  36. LuaTable? functionMetatable;
  37. LuaTable? threadMetatable;
  38. public static LuaState Create()
  39. {
  40. return new();
  41. }
  42. LuaState()
  43. {
  44. mainThread = new(this);
  45. environment = new();
  46. envUpValue = UpValue.Closed(environment);
  47. }
  48. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  49. internal bool TryGetMetatable(LuaValue value, [NotNullWhen(true)] out LuaTable? result)
  50. {
  51. result = value.Type switch
  52. {
  53. LuaValueType.Nil => nilMetatable,
  54. LuaValueType.Boolean => booleanMetatable,
  55. LuaValueType.String => stringMetatable,
  56. LuaValueType.Number => numberMetatable,
  57. LuaValueType.Function => functionMetatable,
  58. LuaValueType.Thread => threadMetatable,
  59. LuaValueType.UserData => value.UnsafeRead<ILuaUserData>().Metatable,
  60. LuaValueType.Table => value.UnsafeRead<LuaTable>().Metatable,
  61. _ => null
  62. };
  63. return result != null;
  64. }
  65. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  66. internal void SetMetatable(LuaValue value, LuaTable metatable)
  67. {
  68. switch (value.Type)
  69. {
  70. case LuaValueType.Nil:
  71. nilMetatable = metatable;
  72. break;
  73. case LuaValueType.Boolean:
  74. booleanMetatable = metatable;
  75. break;
  76. case LuaValueType.String:
  77. stringMetatable = metatable;
  78. break;
  79. case LuaValueType.Number:
  80. numberMetatable = metatable;
  81. break;
  82. case LuaValueType.Function:
  83. functionMetatable = metatable;
  84. break;
  85. case LuaValueType.Thread:
  86. threadMetatable = metatable;
  87. break;
  88. case LuaValueType.UserData:
  89. value.UnsafeRead<ILuaUserData>().Metatable = metatable;
  90. break;
  91. case LuaValueType.Table:
  92. value.UnsafeRead<LuaTable>().Metatable = metatable;
  93. break;
  94. }
  95. }
  96. internal UpValue GetOrAddUpValue(LuaThread thread, int registerIndex)
  97. {
  98. foreach (var upValue in openUpValues.AsSpan())
  99. {
  100. if (upValue.RegisterIndex == registerIndex && upValue.Thread == thread)
  101. {
  102. return upValue;
  103. }
  104. }
  105. var newUpValue = UpValue.Open(thread, registerIndex);
  106. openUpValues.Add(newUpValue);
  107. return newUpValue;
  108. }
  109. internal void CloseUpValues(LuaThread thread, int frameBase)
  110. {
  111. for (int i = 0; i < openUpValues.Length; i++)
  112. {
  113. var upValue = openUpValues[i];
  114. if (upValue.Thread != thread) continue;
  115. if (upValue.RegisterIndex >= frameBase)
  116. {
  117. upValue.Close();
  118. openUpValues.RemoveAtSwapBack(i);
  119. i--;
  120. }
  121. }
  122. }
  123. public unsafe LuaClosure Load(ReadOnlySpan<char> chunk, string chunkName, LuaTable? environment = null)
  124. {
  125. Prototype prototype;
  126. fixed (char* ptr = chunk)
  127. {
  128. prototype = Parser.Parse(this, new(ptr, chunk.Length), chunkName);
  129. }
  130. return new LuaClosure(MainThread, prototype, environment);
  131. }
  132. public LuaClosure Load(ReadOnlySpan<byte> chunk, string chunkName, string mode = "bt", LuaTable? environment = null)
  133. {
  134. if (chunk.Length > 4)
  135. {
  136. if (chunk[0] == '\e')
  137. {
  138. return new LuaClosure(MainThread, Parser.UnDump(chunk, chunkName), environment);
  139. }
  140. }
  141. var charCount = Encoding.UTF8.GetCharCount(chunk);
  142. var pooled = ArrayPool<char>.Shared.Rent(charCount);
  143. try
  144. {
  145. var chars = pooled.AsSpan(0, charCount);
  146. Encoding.UTF8.GetChars(chunk, chars);
  147. return Load(chars, chunkName, environment);
  148. }
  149. finally
  150. {
  151. ArrayPool<char>.Shared.Return(pooled);
  152. }
  153. }
  154. }