MathematicsLibrary.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. namespace Lua.Standard;
  2. public sealed class MathematicsLibrary
  3. {
  4. public static readonly MathematicsLibrary Instance = new();
  5. public const string RandomInstanceKey = "__lua_mathematics_library_random_instance";
  6. public MathematicsLibrary()
  7. {
  8. Functions = [
  9. new("abs", Abs),
  10. new("acos", Acos),
  11. new("asin", Asin),
  12. new("atan2", Atan2),
  13. new("atan", Atan),
  14. new("ceil", Ceil),
  15. new("cos", Cos),
  16. new("cosh", Cosh),
  17. new("deg", Deg),
  18. new("exp", Exp),
  19. new("floor", Floor),
  20. new("fmod", Fmod),
  21. new("frexp", Frexp),
  22. new("ldexp", Ldexp),
  23. new("log", Log),
  24. new("max", Max),
  25. new("min", Min),
  26. new("modf", Modf),
  27. new("pow", Pow),
  28. new("rad", Rad),
  29. new("random", Random),
  30. new("randomseed", RandomSeed),
  31. new("sin", Sin),
  32. new("sinh", Sinh),
  33. new("sqrt", Sqrt),
  34. new("tan", Tan),
  35. new("tanh", Tanh),
  36. ];
  37. }
  38. public readonly LuaFunction[] Functions;
  39. public sealed class RandomUserData(Random random) : ILuaUserData
  40. {
  41. LuaTable? SharedMetatable;
  42. public LuaTable? Metatable { get => SharedMetatable; set => SharedMetatable = value; }
  43. public Random Random { get; } = random;
  44. }
  45. public ValueTask<int> Abs(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  46. {
  47. var arg0 = context.GetArgument<double>(0);
  48. buffer.Span[0] = Math.Abs(arg0);
  49. return new(1);
  50. }
  51. public ValueTask<int> Acos(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  52. {
  53. var arg0 = context.GetArgument<double>(0);
  54. buffer.Span[0] = Math.Acos(arg0);
  55. return new(1);
  56. }
  57. public ValueTask<int> Asin(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  58. {
  59. var arg0 = context.GetArgument<double>(0);
  60. buffer.Span[0] = Math.Asin(arg0);
  61. return new(1);
  62. }
  63. public ValueTask<int> Atan2(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  64. {
  65. var arg0 = context.GetArgument<double>(0);
  66. var arg1 = context.GetArgument<double>(1);
  67. buffer.Span[0] = Math.Atan2(arg0, arg1);
  68. return new(1);
  69. }
  70. public ValueTask<int> Atan(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  71. {
  72. var arg0 = context.GetArgument<double>(0);
  73. buffer.Span[0] = Math.Atan(arg0);
  74. return new(1);
  75. }
  76. public ValueTask<int> Ceil(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  77. {
  78. var arg0 = context.GetArgument<double>(0);
  79. buffer.Span[0] = Math.Ceiling(arg0);
  80. return new(1);
  81. }
  82. public ValueTask<int> Cos(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  83. {
  84. var arg0 = context.GetArgument<double>(0);
  85. buffer.Span[0] = Math.Cos(arg0);
  86. return new(1);
  87. }
  88. public ValueTask<int> Cosh(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  89. {
  90. var arg0 = context.GetArgument<double>(0);
  91. buffer.Span[0] = Math.Cosh(arg0);
  92. return new(1);
  93. }
  94. public ValueTask<int> Deg(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  95. {
  96. var arg0 = context.GetArgument<double>(0);
  97. buffer.Span[0] = arg0 * (180.0 / Math.PI);
  98. return new(1);
  99. }
  100. public ValueTask<int> Exp(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  101. {
  102. var arg0 = context.GetArgument<double>(0);
  103. buffer.Span[0] = Math.Exp(arg0);
  104. return new(1);
  105. }
  106. public ValueTask<int> Floor(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  107. {
  108. var arg0 = context.GetArgument<double>(0);
  109. buffer.Span[0] = Math.Floor(arg0);
  110. return new(1);
  111. }
  112. public ValueTask<int> Fmod(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  113. {
  114. var arg0 = context.GetArgument<double>(0);
  115. var arg1 = context.GetArgument<double>(1);
  116. buffer.Span[0] = arg0 % arg1;
  117. return new(1);
  118. }
  119. public ValueTask<int> Frexp(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  120. {
  121. var arg0 = context.GetArgument<double>(0);
  122. var (m, e) = MathEx.Frexp(arg0);
  123. buffer.Span[0] = m;
  124. buffer.Span[1] = e;
  125. return new(2);
  126. }
  127. public ValueTask<int> Ldexp(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  128. {
  129. var arg0 = context.GetArgument<double>(0);
  130. var arg1 = context.GetArgument<double>(1);
  131. buffer.Span[0] = arg0 * Math.Pow(2, arg1);
  132. return new(1);
  133. }
  134. public ValueTask<int> Log(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  135. {
  136. var arg0 = context.GetArgument<double>(0);
  137. if (context.ArgumentCount == 1)
  138. {
  139. buffer.Span[0] = Math.Log(arg0);
  140. }
  141. else
  142. {
  143. var arg1 = context.GetArgument<double>(1);
  144. buffer.Span[0] = Math.Log(arg0, arg1);
  145. }
  146. return new(1);
  147. }
  148. public ValueTask<int> Max(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  149. {
  150. var x = context.GetArgument<double>(0);
  151. for (int i = 1; i < context.ArgumentCount; i++)
  152. {
  153. x = Math.Max(x, context.GetArgument<double>(i));
  154. }
  155. buffer.Span[0] = x;
  156. return new(1);
  157. }
  158. public ValueTask<int> Min(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  159. {
  160. var x = context.GetArgument<double>(0);
  161. for (int i = 1; i < context.ArgumentCount; i++)
  162. {
  163. x = Math.Min(x, context.GetArgument<double>(i));
  164. }
  165. buffer.Span[0] = x;
  166. return new(1);
  167. }
  168. public ValueTask<int> Modf(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  169. {
  170. var arg0 = context.GetArgument<double>(0);
  171. var (i, f) = MathEx.Modf(arg0);
  172. buffer.Span[0] = i;
  173. buffer.Span[1] = f;
  174. return new(2);
  175. }
  176. public ValueTask<int> Pow(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  177. {
  178. var arg0 = context.GetArgument<double>(0);
  179. var arg1 = context.GetArgument<double>(1);
  180. buffer.Span[0] = Math.Pow(arg0, arg1);
  181. return new(1);
  182. }
  183. public ValueTask<int> Rad(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  184. {
  185. var arg0 = context.GetArgument<double>(0);
  186. buffer.Span[0] = arg0 * (Math.PI / 180.0);
  187. return new(1);
  188. }
  189. public ValueTask<int> Random(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  190. {
  191. var rand = context.State.Environment[RandomInstanceKey].Read<RandomUserData>().Random;
  192. // When we call it without arguments, it returns a pseudo-random real number with uniform distribution in the interval [0,1
  193. if (context.ArgumentCount == 0)
  194. {
  195. buffer.Span[0] = rand.NextDouble();
  196. }
  197. // When we call it with only one argument, an integer n, it returns an integer pseudo-random number such that 1 <= x <= n.
  198. // This is different from the C# random functions.
  199. // See: https://www.lua.org/pil/18.html
  200. else if (context.ArgumentCount == 1)
  201. {
  202. var arg0 = context.GetArgument<int>(0);
  203. if (arg0 < 0)
  204. {
  205. LuaRuntimeException.BadArgument(context.State.GetTraceback(), 0, "random");
  206. }
  207. buffer.Span[0] = rand.Next(1, arg0 + 1);
  208. }
  209. // Finally, we can call random with two integer arguments, l and u, to get a pseudo-random integer x such that l <= x <= u.
  210. else
  211. {
  212. var arg0 = context.GetArgument<int>(0);
  213. var arg1 = context.GetArgument<int>(1);
  214. if (arg0 < 1 || arg1 <= arg0)
  215. {
  216. LuaRuntimeException.BadArgument(context.State.GetTraceback(), 1, "random");
  217. }
  218. buffer.Span[0] = rand.Next(arg0, arg1 + 1);
  219. }
  220. return new(1);
  221. }
  222. public ValueTask<int> RandomSeed(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  223. {
  224. var arg0 = context.GetArgument<double>(0);
  225. context.State.Environment[RandomInstanceKey] = new(new RandomUserData(new Random((int)BitConverter.DoubleToInt64Bits(arg0))));
  226. return new(0);
  227. }
  228. public ValueTask<int> Sin(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  229. {
  230. var arg0 = context.GetArgument<double>(0);
  231. buffer.Span[0] = Math.Sin(arg0);
  232. return new(1);
  233. }
  234. public ValueTask<int> Sinh(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  235. {
  236. var arg0 = context.GetArgument<double>(0);
  237. buffer.Span[0] = Math.Sinh(arg0);
  238. return new(1);
  239. }
  240. public ValueTask<int> Sqrt(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  241. {
  242. var arg0 = context.GetArgument<double>(0);
  243. buffer.Span[0] = Math.Sqrt(arg0);
  244. return new(1);
  245. }
  246. public ValueTask<int> Tan(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  247. {
  248. var arg0 = context.GetArgument<double>(0);
  249. buffer.Span[0] = Math.Tan(arg0);
  250. return new(1);
  251. }
  252. public ValueTask<int> Tanh(LuaFunctionExecutionContext context, Memory<LuaValue> buffer, CancellationToken cancellationToken)
  253. {
  254. var arg0 = context.GetArgument<double>(0);
  255. buffer.Span[0] = Math.Tanh(arg0);
  256. return new(1);
  257. }
  258. }