ScriptRuntimeException.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. using System;
  2. using MoonSharp.Interpreter.Interop;
  3. using MoonSharp.Interpreter.Interop.BasicDescriptors;
  4. namespace MoonSharp.Interpreter
  5. {
  6. /// <summary>
  7. /// Exception for all runtime errors. In addition to constructors, it offers a lot of static methods
  8. /// generating more "standard" Lua errors.
  9. /// </summary>
  10. #if !(PCL || ((!UNITY_EDITOR) && (ENABLE_DOTNET)) || NETFX_CORE)
  11. [Serializable]
  12. #endif
  13. public class ScriptRuntimeException : InterpreterException
  14. {
  15. /// <summary>
  16. /// Initializes a new instance of the <see cref="ScriptRuntimeException"/> class.
  17. /// </summary>
  18. /// <param name="ex">The ex.</param>
  19. public ScriptRuntimeException(Exception ex)
  20. : base(ex)
  21. {
  22. }
  23. /// <summary>
  24. /// Initializes a new instance of the <see cref="ScriptRuntimeException"/> class.
  25. /// </summary>
  26. /// <param name="ex">The ex.</param>
  27. public ScriptRuntimeException(ScriptRuntimeException ex)
  28. : base(ex, ex.DecoratedMessage)
  29. {
  30. this.DecoratedMessage = Message;
  31. this.DoNotDecorateMessage = true;
  32. }
  33. /// <summary>
  34. /// Initializes a new instance of the <see cref="ScriptRuntimeException"/> class.
  35. /// </summary>
  36. /// <param name="message">The message that describes the error.</param>
  37. public ScriptRuntimeException(string message)
  38. : base(message)
  39. {
  40. }
  41. /// <summary>
  42. /// Initializes a new instance of the <see cref="ScriptRuntimeException"/> class.
  43. /// </summary>
  44. /// <param name="format">The format.</param>
  45. /// <param name="args">The arguments.</param>
  46. public ScriptRuntimeException(string format, params object[] args)
  47. : base(format, args)
  48. {
  49. }
  50. /// <summary>
  51. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  52. /// an arithmetic operation was attempted on non-numbers
  53. /// </summary>
  54. /// <param name="l">The left operand.</param>
  55. /// <param name="r">The right operand (or null).</param>
  56. /// <returns>The exception to be raised.</returns>
  57. /// <exception cref="InternalErrorException">If both are numbers</exception>
  58. public static ScriptRuntimeException ArithmeticOnNonNumber(DynValue l, DynValue r = null)
  59. {
  60. if (l.Type != DataType.Number && l.Type != DataType.String)
  61. return new ScriptRuntimeException("attempt to perform arithmetic on a {0} value", l.Type.ToLuaTypeString());
  62. else if (r != null && r.Type != DataType.Number && r.Type != DataType.String)
  63. return new ScriptRuntimeException("attempt to perform arithmetic on a {0} value", r.Type.ToLuaTypeString());
  64. else if (l.Type == DataType.String || (r != null && r.Type == DataType.String))
  65. return new ScriptRuntimeException("attempt to perform arithmetic on a string value");
  66. else
  67. throw new InternalErrorException("ArithmeticOnNonNumber - both are numbers");
  68. }
  69. /// <summary>
  70. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  71. /// a concat operation was attempted on non-strings
  72. /// </summary>
  73. /// <param name="l">The left operand.</param>
  74. /// <param name="r">The right operand.</param>
  75. /// <returns>The exception to be raised.</returns>
  76. /// <exception cref="InternalErrorException">If both are numbers or strings</exception>
  77. public static ScriptRuntimeException ConcatOnNonString(DynValue l, DynValue r)
  78. {
  79. if (l.Type != DataType.Number && l.Type != DataType.String)
  80. return new ScriptRuntimeException("attempt to concatenate a {0} value", l.Type.ToLuaTypeString());
  81. else if (r != null && r.Type != DataType.Number && r.Type != DataType.String)
  82. return new ScriptRuntimeException("attempt to concatenate a {0} value", r.Type.ToLuaTypeString());
  83. else
  84. throw new InternalErrorException("ConcatOnNonString - both are numbers/strings");
  85. }
  86. /// <summary>
  87. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  88. /// a len operator was applied on an invalid operand
  89. /// </summary>
  90. /// <param name="r">The operand.</param>
  91. /// <returns>The exception to be raised.</returns>
  92. public static ScriptRuntimeException LenOnInvalidType(DynValue r)
  93. {
  94. return new ScriptRuntimeException("attempt to get length of a {0} value", r.Type.ToLuaTypeString());
  95. }
  96. /// <summary>
  97. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  98. /// a comparison operator was applied on an invalid combination of operand types
  99. /// </summary>
  100. /// <param name="l">The left operand.</param>
  101. /// <param name="r">The right operand.</param>
  102. /// <returns>The exception to be raised.</returns>
  103. public static ScriptRuntimeException CompareInvalidType(DynValue l, DynValue r)
  104. {
  105. if (l.Type.ToLuaTypeString() == r.Type.ToLuaTypeString())
  106. return new ScriptRuntimeException("attempt to compare two {0} values", l.Type.ToLuaTypeString());
  107. else
  108. return new ScriptRuntimeException("attempt to compare {0} with {1}", l.Type.ToLuaTypeString(), r.Type.ToLuaTypeString());
  109. }
  110. /// <summary>
  111. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  112. /// a function was called with a bad argument
  113. /// </summary>
  114. /// <param name="argNum">The argument number (0-based).</param>
  115. /// <param name="funcName">Name of the function generating this error.</param>
  116. /// <param name="message">The error message.</param>
  117. /// <returns>The exception to be raised.</returns>
  118. public static ScriptRuntimeException BadArgument(int argNum, string funcName, string message)
  119. {
  120. return new ScriptRuntimeException("bad argument #{0} to '{1}' ({2})", argNum + 1, funcName, message);
  121. }
  122. /// <summary>
  123. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  124. /// a function was called with a bad userdata argument
  125. /// </summary>
  126. /// <param name="argNum">The argument number (0-based).</param>
  127. /// <param name="funcName">Name of the function generating this error.</param>
  128. /// <param name="expected">The expected System.Type.</param>
  129. /// <param name="got">The object which was used.</param>
  130. /// <param name="allowNil">True if nils were allowed in this call.</param>
  131. /// <returns>
  132. /// The exception to be raised.
  133. /// </returns>
  134. public static ScriptRuntimeException BadArgumentUserData(int argNum, string funcName, Type expected, object got, bool allowNil)
  135. {
  136. return new ScriptRuntimeException("bad argument #{0} to '{1}' (userdata<{2}>{3} expected, got {4})",
  137. argNum + 1,
  138. funcName,
  139. expected.Name,
  140. allowNil ? "nil or " : "",
  141. got != null ? "userdata<" + got.GetType().Name + ">" : "null"
  142. );
  143. }
  144. /// <summary>
  145. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  146. /// a function was called with a bad argument
  147. /// </summary>
  148. /// <param name="argNum">The argument number (0-based).</param>
  149. /// <param name="funcName">Name of the function generating this error.</param>
  150. /// <param name="expected">The expected data type.</param>
  151. /// <param name="got">The data type received.</param>
  152. /// <param name="allowNil">True if nils were allowed in this call.</param>
  153. /// <returns>
  154. /// The exception to be raised.
  155. /// </returns>
  156. public static ScriptRuntimeException BadArgument(int argNum, string funcName, DataType expected, DataType got, bool allowNil)
  157. {
  158. return BadArgument(argNum, funcName, expected.ToErrorTypeString(), got.ToErrorTypeString(), allowNil);
  159. }
  160. /// <summary>
  161. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  162. /// a function was called with a bad argument
  163. /// </summary>
  164. /// <param name="argNum">The argument number (0-based).</param>
  165. /// <param name="funcName">Name of the function generating this error.</param>
  166. /// <param name="expected">The expected type description.</param>
  167. /// <param name="got">The description of the type received.</param>
  168. /// <param name="allowNil">True if nils were allowed in this call.</param>
  169. /// <returns>
  170. /// The exception to be raised.
  171. /// </returns>
  172. public static ScriptRuntimeException BadArgument(int argNum, string funcName, string expected, string got, bool allowNil)
  173. {
  174. return new ScriptRuntimeException("bad argument #{0} to '{1}' ({2}{3} expected, got {4})",
  175. argNum + 1, funcName, allowNil ? "nil or " : "", expected, got);
  176. }
  177. /// <summary>
  178. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  179. /// a function was called with no value when a value was required.
  180. ///
  181. /// This function creates a message like "bad argument #xxx to 'yyy' (zzz expected, got no value)"
  182. /// while <see cref="BadArgumentValueExpected" /> creates a message like "bad argument #xxx to 'yyy' (value expected)"
  183. /// </summary>
  184. /// <param name="argNum">The argument number (0-based).</param>
  185. /// <param name="funcName">Name of the function generating this error.</param>
  186. /// <param name="expected">The expected data type.</param>
  187. /// <returns>
  188. /// The exception to be raised.
  189. /// </returns>
  190. public static ScriptRuntimeException BadArgumentNoValue(int argNum, string funcName, DataType expected)
  191. {
  192. return new ScriptRuntimeException("bad argument #{0} to '{1}' ({2} expected, got no value)",
  193. argNum + 1, funcName, expected.ToErrorTypeString());
  194. }
  195. /// <summary>
  196. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  197. /// an out of range index was specified
  198. /// </summary>
  199. /// <param name="argNum">The argument number (0-based).</param>
  200. /// <param name="funcName">Name of the function generating this error.</param>
  201. /// <returns>
  202. /// The exception to be raised.
  203. /// </returns>
  204. public static ScriptRuntimeException BadArgumentIndexOutOfRange(string funcName, int argNum)
  205. {
  206. return new ScriptRuntimeException("bad argument #{0} to '{1}' (index out of range)", argNum + 1, funcName);
  207. }
  208. /// <summary>
  209. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  210. /// a function was called with a negative number when a positive one was expected.
  211. /// </summary>
  212. /// <param name="argNum">The argument number (0-based).</param>
  213. /// <param name="funcName">Name of the function generating this error.</param>
  214. /// <returns>
  215. /// The exception to be raised.
  216. /// </returns>
  217. public static ScriptRuntimeException BadArgumentNoNegativeNumbers(int argNum, string funcName)
  218. {
  219. return new ScriptRuntimeException("bad argument #{0} to '{1}' (not a non-negative number in proper range)",
  220. argNum + 1, funcName);
  221. }
  222. /// <summary>
  223. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  224. /// a function was called with no value when a value was required.
  225. /// This function creates a message like "bad argument #xxx to 'yyy' (value expected)"
  226. /// while <see cref="BadArgumentNoValue" /> creates a message like "bad argument #xxx to 'yyy' (zzz expected, got no value)"
  227. /// </summary>
  228. /// <param name="argNum">The argument number (0-based).</param>
  229. /// <param name="funcName">Name of the function generating this error.</param>
  230. /// <returns>
  231. /// The exception to be raised.
  232. /// </returns>
  233. public static ScriptRuntimeException BadArgumentValueExpected(int argNum, string funcName)
  234. {
  235. return new ScriptRuntimeException("bad argument #{0} to '{1}' (value expected)",
  236. argNum + 1, funcName);
  237. }
  238. /// <summary>
  239. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  240. /// an invalid attempt to index the specified object was made
  241. /// </summary>
  242. /// <param name="obj">The object.</param>
  243. /// <returns>
  244. /// The exception to be raised.
  245. /// </returns>
  246. public static ScriptRuntimeException IndexType(DynValue obj)
  247. {
  248. return new ScriptRuntimeException("attempt to index a {0} value", obj.Type.ToLuaTypeString());
  249. }
  250. /// <summary>
  251. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  252. /// a loop was detected when performing __index over metatables.
  253. /// </summary>
  254. /// <returns>
  255. /// The exception to be raised.
  256. /// </returns>
  257. public static ScriptRuntimeException LoopInIndex()
  258. {
  259. return new ScriptRuntimeException("loop in gettable");
  260. }
  261. /// <summary>
  262. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  263. /// a loop was detected when performing __newindex over metatables.
  264. /// </summary>
  265. /// <returns>
  266. /// The exception to be raised.
  267. /// </returns>
  268. public static ScriptRuntimeException LoopInNewIndex()
  269. {
  270. return new ScriptRuntimeException("loop in settable");
  271. }
  272. /// <summary>
  273. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  274. /// a loop was detected when performing __call over metatables.
  275. /// </summary>
  276. /// <returns>
  277. /// The exception to be raised.
  278. /// </returns>
  279. public static ScriptRuntimeException LoopInCall()
  280. {
  281. return new ScriptRuntimeException("loop in call");
  282. }
  283. /// <summary>
  284. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  285. /// a table indexing operation used nil as the key.
  286. /// </summary>
  287. /// <returns>
  288. /// The exception to be raised.
  289. /// </returns>
  290. public static ScriptRuntimeException TableIndexIsNil()
  291. {
  292. return new ScriptRuntimeException("table index is nil");
  293. }
  294. /// <summary>
  295. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  296. /// a table indexing operation used a NaN as the key.
  297. /// </summary>
  298. /// <returns>
  299. /// The exception to be raised.
  300. /// </returns>
  301. public static ScriptRuntimeException TableIndexIsNaN()
  302. {
  303. return new ScriptRuntimeException("table index is NaN");
  304. }
  305. /// <summary>
  306. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  307. /// a conversion to number failed.
  308. /// </summary>
  309. /// <param name="stage">
  310. /// Selects the correct error message:
  311. /// 0 - "value must be a number"
  312. /// 1 - "'for' initial value must be a number"
  313. /// 2 - "'for' step must be a number"
  314. /// 3 - "'for' limit must be a number"
  315. /// </param>
  316. /// <returns>
  317. /// The exception to be raised.
  318. /// </returns>
  319. public static ScriptRuntimeException ConvertToNumberFailed(int stage)
  320. {
  321. switch (stage)
  322. {
  323. case 1:
  324. return new ScriptRuntimeException("'for' initial value must be a number");
  325. case 2:
  326. return new ScriptRuntimeException("'for' step must be a number");
  327. case 3:
  328. return new ScriptRuntimeException("'for' limit must be a number");
  329. default:
  330. return new ScriptRuntimeException("value must be a number");
  331. }
  332. }
  333. /// <summary>
  334. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  335. /// a conversion of a CLR type to a Lua type has failed.
  336. /// </summary>
  337. /// <param name="obj">The object which could not be converted.</param>
  338. /// <returns>
  339. /// The exception to be raised.
  340. /// </returns>
  341. public static ScriptRuntimeException ConvertObjectFailed(object obj)
  342. {
  343. return new ScriptRuntimeException("cannot convert clr type {0}", obj.GetType());
  344. }
  345. /// <summary>
  346. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  347. /// a conversion of a Lua type to a CLR type has failed.
  348. /// </summary>
  349. /// <param name="t">The Lua type.</param>
  350. /// <returns>
  351. /// The exception to be raised.
  352. /// </returns>
  353. public static ScriptRuntimeException ConvertObjectFailed(DataType t)
  354. {
  355. return new ScriptRuntimeException("cannot convert a {0} to a clr type", t.ToString().ToLowerInvariant());
  356. }
  357. /// <summary>
  358. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  359. /// a constrained conversion of a Lua type to a CLR type has failed.
  360. /// </summary>
  361. /// <param name="t">The Lua type.</param>
  362. /// <param name="t2">The expected CLR type.</param>
  363. /// <returns>
  364. /// The exception to be raised.
  365. /// </returns>
  366. public static ScriptRuntimeException ConvertObjectFailed(DataType t, Type t2)
  367. {
  368. return new ScriptRuntimeException("cannot convert a {0} to a clr type {1}", t.ToString().ToLowerInvariant(), t2.FullName);
  369. }
  370. /// <summary>
  371. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  372. /// a userdata of a specific CLR type was expected and a non-userdata type was passed.
  373. /// </summary>
  374. /// <param name="t">The Lua type.</param>
  375. /// <param name="clrType">The expected CLR type.</param>
  376. /// <returns>
  377. /// The exception to be raised.
  378. /// </returns>
  379. public static ScriptRuntimeException UserDataArgumentTypeMismatch(DataType t, Type clrType)
  380. {
  381. return new ScriptRuntimeException("cannot find a conversion from a MoonSharp {0} to a clr {1}", t.ToString().ToLowerInvariant(), clrType.FullName);
  382. }
  383. /// <summary>
  384. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  385. /// an attempt to index an invalid member of a userdata was done.
  386. /// </summary>
  387. /// <param name="typename">The name of the userdata type.</param>
  388. /// <param name="fieldname">The field name.</param>
  389. /// <returns>
  390. /// The exception to be raised.
  391. /// </returns>
  392. public static ScriptRuntimeException UserDataMissingField(string typename, string fieldname)
  393. {
  394. return new ScriptRuntimeException("cannot access field {0} of userdata<{1}>", fieldname, typename);
  395. }
  396. /// <summary>
  397. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  398. /// an attempt resume a coroutine in an invalid state was done.
  399. /// </summary>
  400. /// <param name="state">The state of the coroutine.</param>
  401. /// <returns>
  402. /// The exception to be raised.
  403. /// </returns>
  404. public static ScriptRuntimeException CannotResumeNotSuspended(CoroutineState state)
  405. {
  406. if (state == CoroutineState.Dead)
  407. return new ScriptRuntimeException("cannot resume dead coroutine");
  408. else
  409. return new ScriptRuntimeException("cannot resume non-suspended coroutine");
  410. }
  411. /// <summary>
  412. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  413. /// an attempt to yield across a CLR boundary was made.
  414. /// </summary>
  415. /// <returns>
  416. /// The exception to be raised.
  417. /// </returns>
  418. public static ScriptRuntimeException CannotYield()
  419. {
  420. return new ScriptRuntimeException("attempt to yield across a CLR-call boundary");
  421. }
  422. /// <summary>
  423. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  424. /// an attempt to yield from the main coroutine was made.
  425. /// </summary>
  426. /// <returns>
  427. /// The exception to be raised.
  428. /// </returns>
  429. public static ScriptRuntimeException CannotYieldMain()
  430. {
  431. return new ScriptRuntimeException("attempt to yield from outside a coroutine");
  432. }
  433. /// <summary>
  434. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  435. /// an attempt to call a non-function was made
  436. /// </summary>
  437. /// <param name="type">The lua non-function data type.</param>
  438. /// <param name="debugText">The debug text to aid location (appears as "near 'xxx'").</param>
  439. /// <returns></returns>
  440. public static ScriptRuntimeException AttemptToCallNonFunc(DataType type, string debugText = null)
  441. {
  442. string functype = type.ToErrorTypeString();
  443. if (debugText != null)
  444. return new ScriptRuntimeException("attempt to call a {0} value near '{1}'", functype, debugText);
  445. else
  446. return new ScriptRuntimeException("attempt to call a {0} value", functype);
  447. }
  448. /// <summary>
  449. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  450. /// an attempt to access a non-static member from a static userdata was made
  451. /// </summary>
  452. /// <param name="desc">The member descriptor.</param>
  453. public static ScriptRuntimeException AccessInstanceMemberOnStatics(IMemberDescriptor desc)
  454. {
  455. return new ScriptRuntimeException("attempt to access instance member {0} from a static userdata", desc.Name);
  456. }
  457. /// <summary>
  458. /// Creates a ScriptRuntimeException with a predefined error message specifying that
  459. /// an attempt to access a non-static member from a static userdata was made
  460. /// </summary>
  461. /// <param name="typeDescr">The type descriptor.</param>
  462. /// <param name="desc">The member descriptor.</param>
  463. /// <returns></returns>
  464. public static ScriptRuntimeException AccessInstanceMemberOnStatics(IUserDataDescriptor typeDescr, IMemberDescriptor desc)
  465. {
  466. return new ScriptRuntimeException("attempt to access instance member {0}.{1} from a static userdata", typeDescr.Name, desc.Name);
  467. }
  468. /// <summary>
  469. /// Rethrows this instance if
  470. /// </summary>
  471. /// <returns></returns>
  472. public override void Rethrow()
  473. {
  474. if (Script.GlobalOptions.RethrowExceptionNested)
  475. throw new ScriptRuntimeException(this);
  476. }
  477. }
  478. }