BitwiseLibrary.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. using Lua.Standard.Internal;
  2. namespace Lua.Standard;
  3. public sealed class BitwiseLibrary
  4. {
  5. public static readonly BitwiseLibrary Instance = new();
  6. public BitwiseLibrary()
  7. {
  8. var libraryName = "bit32";
  9. Functions =
  10. [
  11. new(libraryName, "arshift", ArShift),
  12. new(libraryName, "band", BAnd),
  13. new(libraryName, "bnot", BNot),
  14. new(libraryName, "bor", BOr),
  15. new(libraryName, "btest", BTest),
  16. new(libraryName, "bxor", BXor),
  17. new(libraryName, "extract", Extract),
  18. new(libraryName, "lrotate", LRotate),
  19. new(libraryName, "lshift", LShift),
  20. new(libraryName, "replace", Replace),
  21. new(libraryName, "rrotate", RRotate),
  22. new(libraryName, "rshift", RShift)
  23. ];
  24. }
  25. public readonly LibraryFunction[] Functions;
  26. public ValueTask<int> ArShift(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  27. {
  28. var x = context.GetArgument<double>(0);
  29. var disp = context.GetArgument<double>(1);
  30. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, x);
  31. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 2, disp);
  32. var v = Bit32Helper.ToInt32(x);
  33. var a = (int)disp;
  34. if (a < 0)
  35. {
  36. v <<= -a;
  37. }
  38. else
  39. {
  40. v >>= a;
  41. }
  42. return new(context.Return((uint)v));
  43. }
  44. public ValueTask<int> BAnd(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  45. {
  46. if (context.ArgumentCount == 0)
  47. {
  48. context.Return(uint.MaxValue);
  49. return default;
  50. }
  51. var arg0 = context.GetArgument<double>(0);
  52. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, arg0);
  53. var value = Bit32Helper.ToUInt32(arg0);
  54. for (var i = 1; i < context.ArgumentCount; i++)
  55. {
  56. var arg = context.GetArgument<double>(i);
  57. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1 + i, arg);
  58. var v = Bit32Helper.ToUInt32(arg);
  59. value &= v;
  60. }
  61. return new(context.Return(value));
  62. }
  63. public ValueTask<int> BNot(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  64. {
  65. var arg0 = context.GetArgument<double>(0);
  66. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, arg0);
  67. var value = Bit32Helper.ToUInt32(arg0);
  68. return new(context.Return(~value));
  69. }
  70. public ValueTask<int> BOr(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  71. {
  72. if (context.ArgumentCount == 0)
  73. {
  74. return new(context.Return(0));
  75. }
  76. var arg0 = context.GetArgument<double>(0);
  77. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, arg0);
  78. var value = Bit32Helper.ToUInt32(arg0);
  79. for (var i = 1; i < context.ArgumentCount; i++)
  80. {
  81. var arg = context.GetArgument<double>(i);
  82. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1 + i, arg);
  83. var v = Bit32Helper.ToUInt32(arg);
  84. value |= v;
  85. }
  86. return new(context.Return(value));
  87. }
  88. public ValueTask<int> BTest(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  89. {
  90. if (context.ArgumentCount == 0)
  91. {
  92. ;
  93. return new(context.Return(true));
  94. }
  95. var arg0 = context.GetArgument<double>(0);
  96. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, arg0);
  97. var value = Bit32Helper.ToUInt32(arg0);
  98. for (var i = 1; i < context.ArgumentCount; i++)
  99. {
  100. var arg = context.GetArgument<double>(i);
  101. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1 + i, arg);
  102. var v = Bit32Helper.ToUInt32(arg);
  103. value &= v;
  104. }
  105. return new(context.Return(value != 0));
  106. }
  107. public ValueTask<int> BXor(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  108. {
  109. if (context.ArgumentCount == 0)
  110. {
  111. return new(context.Return(0));
  112. }
  113. var arg0 = context.GetArgument<double>(0);
  114. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, arg0);
  115. var value = Bit32Helper.ToUInt32(arg0);
  116. for (var i = 1; i < context.ArgumentCount; i++)
  117. {
  118. var arg = context.GetArgument<double>(i);
  119. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1 + i, arg);
  120. var v = Bit32Helper.ToUInt32(arg);
  121. value ^= v;
  122. }
  123. return new(context.Return(value));
  124. }
  125. public ValueTask<int> Extract(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  126. {
  127. var arg0 = context.GetArgument<double>(0);
  128. var arg1 = context.GetArgument<double>(1);
  129. var arg2 = context.HasArgument(2)
  130. ? context.GetArgument<double>(2)
  131. : 1;
  132. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, arg0);
  133. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 2, arg1);
  134. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 3, arg2);
  135. var n = Bit32Helper.ToUInt32(arg0);
  136. var field = (int)arg1;
  137. var width = (int)arg2;
  138. Bit32Helper.ValidateFieldAndWidth(context.Thread, "extract", 2, field, width);
  139. if (field == 0 && width == 32)
  140. {
  141. return new(context.Return(n));
  142. }
  143. else
  144. {
  145. var mask = (uint)((1 << width) - 1);
  146. return new(context.Return((n >> field) & mask));
  147. }
  148. }
  149. public ValueTask<int> LRotate(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  150. {
  151. var x = context.GetArgument<double>(0);
  152. var disp = context.GetArgument<double>(1);
  153. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, x);
  154. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 2, disp);
  155. var v = Bit32Helper.ToUInt32(x);
  156. var a = (int)disp % 32;
  157. if (a < 0)
  158. {
  159. v = (v >> -a) | (v << (32 + a));
  160. }
  161. else
  162. {
  163. v = (v << a) | (v >> (32 - a));
  164. }
  165. ;
  166. return new(context.Return(v));
  167. }
  168. public ValueTask<int> LShift(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  169. {
  170. var x = context.GetArgument<double>(0);
  171. var disp = context.GetArgument<double>(1);
  172. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, x);
  173. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 2, disp);
  174. var v = Bit32Helper.ToUInt32(x);
  175. var a = (int)disp;
  176. if (Math.Abs(a) >= 32)
  177. {
  178. v = 0;
  179. }
  180. else if (a < 0)
  181. {
  182. v >>= -a;
  183. }
  184. else
  185. {
  186. v <<= a;
  187. }
  188. return new(context.Return(v));
  189. }
  190. public ValueTask<int> Replace(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  191. {
  192. var arg0 = context.GetArgument<double>(0);
  193. var arg1 = context.GetArgument<double>(1);
  194. var arg2 = context.GetArgument<double>(2);
  195. var arg3 = context.HasArgument(3)
  196. ? context.GetArgument<double>(3)
  197. : 1;
  198. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, arg0);
  199. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 2, arg1);
  200. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 3, arg2);
  201. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 4, arg3);
  202. var n = Bit32Helper.ToUInt32(arg0);
  203. var v = Bit32Helper.ToUInt32(arg1);
  204. var field = (int)arg2;
  205. var width = (int)arg3;
  206. Bit32Helper.ValidateFieldAndWidth(context.Thread, "replace", 2, field, width);
  207. uint mask;
  208. if (width == 32)
  209. {
  210. mask = 0xFFFFFFFF;
  211. }
  212. else
  213. {
  214. mask = (uint)((1 << width) - 1);
  215. }
  216. v = v & mask;
  217. n = (n & ~(mask << field)) | (v << field);
  218. return new(context.Return(n));
  219. }
  220. public ValueTask<int> RRotate(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  221. {
  222. var x = context.GetArgument<double>(0);
  223. var disp = context.GetArgument<double>(1);
  224. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, x);
  225. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 2, disp);
  226. var v = Bit32Helper.ToUInt32(x);
  227. var a = (int)disp % 32;
  228. if (a < 0)
  229. {
  230. v = (v << -a) | (v >> (32 + a));
  231. }
  232. else
  233. {
  234. v = (v >> a) | (v << (32 - a));
  235. }
  236. return new(context.Return(v));
  237. }
  238. public ValueTask<int> RShift(LuaFunctionExecutionContext context, CancellationToken cancellationToken)
  239. {
  240. var x = context.GetArgument<double>(0);
  241. var disp = context.GetArgument<double>(1);
  242. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 1, x);
  243. LuaRuntimeException.ThrowBadArgumentIfNumberIsNotInteger(context.Thread, 2, disp);
  244. var v = Bit32Helper.ToUInt32(x);
  245. var a = (int)disp;
  246. if (Math.Abs(a) >= 32)
  247. {
  248. v = 0;
  249. }
  250. else if (a < 0)
  251. {
  252. v <<= -a;
  253. }
  254. else
  255. {
  256. v >>= a;
  257. }
  258. return new(context.Return(v));
  259. }
  260. }