LuaFunctionExecutionContext.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using System.Runtime.CompilerServices;
  2. using System.Runtime.InteropServices;
  3. using Lua.CodeAnalysis;
  4. using Lua.Runtime;
  5. namespace Lua;
  6. [StructLayout(LayoutKind.Auto)]
  7. public readonly record struct LuaFunctionExecutionContext
  8. {
  9. public required LuaState State { get; init; }
  10. public required LuaThread Thread { get; init; }
  11. public required int ArgumentCount { get; init; }
  12. public required int FrameBase { get; init; }
  13. public SourcePosition? SourcePosition { get; init; }
  14. public string? RootChunkName { get; init; }
  15. public string? ChunkName { get; init; }
  16. public int? CallerInstructionIndex { get; init; }
  17. public object? AdditionalContext { get; init; }
  18. public ReadOnlySpan<LuaValue> Arguments
  19. {
  20. get { return Thread.GetStackValues().Slice(FrameBase, ArgumentCount); }
  21. }
  22. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  23. public bool HasArgument(int index)
  24. {
  25. return ArgumentCount > index && Arguments[index].Type is not LuaValueType.Nil;
  26. }
  27. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  28. public LuaValue GetArgument(int index)
  29. {
  30. ThrowIfArgumentNotExists(index);
  31. return Arguments[index];
  32. }
  33. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  34. internal LuaValue GetArgumentOrDefault(int index, LuaValue defaultValue = default)
  35. {
  36. if (ArgumentCount <= index)
  37. {
  38. return defaultValue;
  39. }
  40. return Arguments[index];
  41. }
  42. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  43. public T GetArgument<T>(int index)
  44. {
  45. ThrowIfArgumentNotExists(index);
  46. var arg = Arguments[index];
  47. if (!arg.TryRead<T>(out var argValue))
  48. {
  49. var t = typeof(T);
  50. if ((t == typeof(int) || t == typeof(long)) && arg.TryReadNumber(out _))
  51. {
  52. LuaRuntimeException.BadArgumentNumberIsNotInteger(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name);
  53. }
  54. else if (LuaValue.TryGetLuaValueType(t, out var type))
  55. {
  56. LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, type.ToString(), arg.Type.ToString());
  57. }
  58. else if (arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
  59. {
  60. LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.UnsafeRead<object>()?.GetType().ToString() ?? "userdata: 0");
  61. }
  62. else
  63. {
  64. LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.Type.ToString());
  65. }
  66. }
  67. return argValue;
  68. }
  69. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  70. internal T GetArgumentOrDefault<T>(int index, T defaultValue = default!)
  71. {
  72. if (ArgumentCount <= index)
  73. {
  74. return defaultValue;
  75. }
  76. var arg = Arguments[index];
  77. if (arg.Type is LuaValueType.Nil)
  78. {
  79. return defaultValue;
  80. }
  81. if (!arg.TryRead<T>(out var argValue))
  82. {
  83. var t = typeof(T);
  84. if ((t == typeof(int) || t == typeof(long)) && arg.TryReadNumber(out _))
  85. {
  86. LuaRuntimeException.BadArgumentNumberIsNotInteger(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name);
  87. }
  88. else if (LuaValue.TryGetLuaValueType(t, out var type))
  89. {
  90. LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, type.ToString(), arg.Type.ToString());
  91. }
  92. else if (arg.Type is LuaValueType.UserData or LuaValueType.LightUserData)
  93. {
  94. LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.UnsafeRead<object>()?.GetType().ToString() ?? "userdata: 0");
  95. }
  96. else
  97. {
  98. LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name, t.Name, arg.Type.ToString());
  99. }
  100. }
  101. return argValue;
  102. }
  103. public CSharpClosure? GetCsClosure()
  104. {
  105. return Thread.GetCurrentFrame().Function as CSharpClosure;
  106. }
  107. internal void ThrowBadArgument(int index, string message)
  108. {
  109. LuaRuntimeException.BadArgument(State.GetTraceback(), index, Thread.GetCurrentFrame().Function.Name, message);
  110. }
  111. void ThrowIfArgumentNotExists(int index)
  112. {
  113. if (ArgumentCount <= index)
  114. {
  115. LuaRuntimeException.BadArgument(State.GetTraceback(), index + 1, Thread.GetCurrentFrame().Function.Name);
  116. }
  117. }
  118. }