Exceptions.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using Lua.CodeAnalysis;
  2. using Lua.CodeAnalysis.Syntax;
  3. using Lua.Internal;
  4. using Lua.Runtime;
  5. namespace Lua;
  6. public class LuaException : Exception
  7. {
  8. protected LuaException(Exception innerException) : base(innerException.Message, innerException)
  9. {
  10. }
  11. protected LuaException(string message, Exception innerException) : base(message, innerException)
  12. {
  13. }
  14. public LuaException(string message) : base(message)
  15. {
  16. }
  17. protected LuaException()
  18. {
  19. }
  20. }
  21. public class LuaParseException(string? chunkName, SourcePosition position, string message) : LuaException(message)
  22. {
  23. public string? ChunkName { get; } = chunkName;
  24. public SourcePosition Position { get; } = position;
  25. public static void UnexpectedToken(string? chunkName, SourcePosition position, SyntaxToken token)
  26. {
  27. throw new LuaParseException(chunkName, position, $"unexpected symbol <{token.Type}> near '{token.Text}'");
  28. }
  29. public static void ExpectedToken(string? chunkName, SourcePosition position, SyntaxTokenType token)
  30. {
  31. throw new LuaParseException(chunkName, position, $"'{token}' expected");
  32. }
  33. public static void UnfinishedLongComment(string? chunkName, SourcePosition position)
  34. {
  35. throw new LuaParseException(chunkName, position, $"unfinished long comment (starting at line {position.Line})");
  36. }
  37. public static void SyntaxError(string? chunkName, SourcePosition position, SyntaxToken? token)
  38. {
  39. throw new LuaParseException(chunkName, position, $"syntax error {(token == null ? "" : $"near '{token.Value.Text}'")}");
  40. }
  41. public static void NoVisibleLabel(string label, string? chunkName, SourcePosition position)
  42. {
  43. throw new LuaParseException(chunkName, position, $"no visible label '{label}' for <goto>");
  44. }
  45. public static void BreakNotInsideALoop(string? chunkName, SourcePosition position)
  46. {
  47. throw new LuaParseException(chunkName, position, "<break> not inside a loop");
  48. }
  49. public override string Message => $"{ChunkName}:{Position.Line}: {base.Message}";
  50. }
  51. public class LuaCompileException(string chunkName, SourcePosition position, int offset, string message, string? nearToken) : LuaException(GetMessageWithNearToken(message, nearToken))
  52. {
  53. public string ChunkName { get; } = chunkName;
  54. public int OffSet { get; } = offset;
  55. public SourcePosition Position => position;
  56. public string MainMessage => message;
  57. public string? NearToken => nearToken;
  58. public string MessageWithNearToken => base.Message;
  59. public override string Message => $"{ChunkName}:{Position.Line}: {base.Message}";
  60. static string GetMessageWithNearToken(string message, string? nearToken)
  61. {
  62. if (string.IsNullOrEmpty(nearToken))
  63. {
  64. return message;
  65. }
  66. return $"{message} near {nearToken}";
  67. }
  68. }
  69. public class LuaUnDumpException(string message) : LuaException(message);
  70. public class LuaRuntimeException : LuaException
  71. {
  72. public LuaRuntimeException(LuaThread? thread, Exception innerException) : base(innerException)
  73. {
  74. Thread = thread;
  75. }
  76. public LuaRuntimeException(LuaThread? thread, LuaValue errorObject)
  77. {
  78. Thread = thread;
  79. ErrorObject = errorObject;
  80. }
  81. public Traceback? LuaTraceback { get; private set; }
  82. internal LuaThread? Thread { get; private set; } = default!;
  83. public LuaValue ErrorObject { get; }
  84. public static void AttemptInvalidOperation(LuaThread? traceback, string op, LuaValue a, LuaValue b)
  85. {
  86. throw new LuaRuntimeException(traceback, $"attempt to {op} a '{a.Type}' with a '{b.Type}'");
  87. }
  88. public static void AttemptInvalidOperation(LuaThread? traceback, string op, LuaValue a)
  89. {
  90. throw new LuaRuntimeException(traceback, $"attempt to {op} a '{a.Type}' value");
  91. }
  92. public static void BadArgument(LuaThread? traceback, int argumentId, string functionName)
  93. {
  94. throw new LuaRuntimeException(traceback, $"bad argument #{argumentId} to '{functionName}' (value expected)");
  95. }
  96. public static void BadArgument(LuaThread? traceback, int argumentId, string functionName, LuaValueType[] expected)
  97. {
  98. throw new LuaRuntimeException(traceback, $"bad argument #{argumentId} to '{functionName}' ({string.Join(" or ", expected)} expected)");
  99. }
  100. public static void BadArgument(LuaThread? traceback, int argumentId, string functionName, string expected, string actual)
  101. {
  102. throw new LuaRuntimeException(traceback, $"bad argument #{argumentId} to '{functionName}' ({expected} expected, got {actual})");
  103. }
  104. public static void BadArgument(LuaThread? traceback, int argumentId, string functionName, string message)
  105. {
  106. throw new LuaRuntimeException(traceback, $"bad argument #{argumentId} to '{functionName}' ({message})");
  107. }
  108. public static void BadArgumentNumberIsNotInteger(LuaThread? thread, int argumentId, string functionName)
  109. {
  110. throw new LuaRuntimeException(thread, $"bad argument #{argumentId} to '{functionName}' (number has no integer representation)");
  111. }
  112. public static void ThrowBadArgumentIfNumberIsNotInteger(LuaThread? thread, string functionName, int argumentId, double value)
  113. {
  114. if (!MathEx.IsInteger(value))
  115. {
  116. BadArgumentNumberIsNotInteger(thread, argumentId, functionName);
  117. }
  118. }
  119. static string CreateMessage(Traceback traceback, LuaValue errorObject)
  120. {
  121. var pooledList = new PooledList<char>(64);
  122. pooledList.Clear();
  123. try
  124. {
  125. pooledList.AddRange("Lua-CSharp: ");
  126. traceback.WriteLastLuaTrace(ref pooledList);
  127. pooledList.AddRange(": ");
  128. pooledList.AddRange($"{errorObject}");
  129. return pooledList.AsSpan().ToString();
  130. }
  131. finally
  132. {
  133. pooledList.Dispose();
  134. }
  135. }
  136. internal void BuildWithPop(int top)
  137. {
  138. if (Thread != null)
  139. {
  140. var callStack = Thread.CallStack.AsSpan()[top..];
  141. if (callStack.IsEmpty) return;
  142. LuaTraceback = new Traceback(Thread.State) { RootFunc = callStack[0].Function, StackFrames = callStack[1..].ToArray(), };
  143. Thread.CallStack.PopUntil(top);
  144. }
  145. }
  146. public override string Message
  147. {
  148. get
  149. {
  150. if (InnerException != null) return InnerException.Message;
  151. if (LuaTraceback == null)
  152. {
  153. return ErrorObject.ToString();
  154. }
  155. return CreateMessage(LuaTraceback, ErrorObject);
  156. }
  157. }
  158. public override string ToString()
  159. {
  160. if (LuaTraceback == null)
  161. return base.ToString();
  162. var pooledList = new PooledList<char>(64);
  163. pooledList.Clear();
  164. try
  165. {
  166. pooledList.AddRange(Message);
  167. pooledList.Add('\n');
  168. pooledList.AddRange(LuaTraceback.ToString());
  169. pooledList.Add('\n');
  170. pooledList.AddRange(StackTrace);
  171. return pooledList.AsSpan().ToString();
  172. }
  173. finally
  174. {
  175. pooledList.Dispose();
  176. }
  177. //return $"{Message} {StackTrace}";
  178. }
  179. }
  180. public class LuaAssertionException(LuaThread? traceback, string message) : LuaRuntimeException(traceback, message)
  181. {
  182. // public override string ToString()
  183. // {
  184. // return $"{Message}\n{StackTrace}";
  185. // }
  186. }
  187. public class LuaModuleNotFoundException(string moduleName) : LuaException($"module '{moduleName}' not found");