PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/error.c

https://github.com/emboss/mruby
C | 414 lines | 311 code | 54 blank | 49 comment | 44 complexity | c1156a1099216b50b1901b584be073d7 MD5 | raw file
  1. /*
  2. ** error.c - Exception class
  3. **
  4. ** See Copyright Notice in mruby.h
  5. */
  6. #include "mruby.h"
  7. #include <stdarg.h>
  8. #include <stdio.h>
  9. #include <setjmp.h>
  10. #include <string.h>
  11. #include "error.h"
  12. #include "mruby/variable.h"
  13. #include "mruby/string.h"
  14. #include "mruby/class.h"
  15. #include "mruby/proc.h"
  16. #include "mruby/irep.h"
  17. #define warn_printf printf
  18. mrb_value
  19. mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
  20. {
  21. return mrb_funcall(mrb, mrb_obj_value(c), "new", 1, mrb_str_new(mrb, ptr, len));
  22. }
  23. mrb_value
  24. mrb_exc_new3(mrb_state *mrb, struct RClass* c, mrb_value str)
  25. {
  26. //StringValue(str);
  27. mrb_string_value(mrb, &str);
  28. return mrb_funcall(mrb, mrb_obj_value(c), "new", 1, str);
  29. }
  30. /*
  31. * call-seq:
  32. * Exception.new(msg = nil) -> exception
  33. *
  34. * Construct a new Exception object, optionally passing in
  35. * a message.
  36. */
  37. static mrb_value
  38. exc_initialize(mrb_state *mrb, mrb_value exc)
  39. {
  40. mrb_value mesg;
  41. if (mrb_get_args(mrb, "|o", &mesg) == 1) {
  42. mrb_iv_set(mrb, exc, mrb_intern(mrb, "mesg"), mesg);
  43. }
  44. return exc;
  45. }
  46. /*
  47. * Document-method: exception
  48. *
  49. * call-seq:
  50. * exc.exception(string) -> an_exception or exc
  51. *
  52. * With no argument, or if the argument is the same as the receiver,
  53. * return the receiver. Otherwise, create a new
  54. * exception object of the same class as the receiver, but with a
  55. * message equal to <code>string.to_str</code>.
  56. *
  57. */
  58. static mrb_value
  59. exc_exception(mrb_state *mrb, mrb_value self)
  60. {
  61. mrb_value exc;
  62. mrb_value a;
  63. int argc;
  64. argc = mrb_get_args(mrb, "|o", &a);
  65. if (argc == 0) return self;
  66. if (mrb_obj_equal(mrb, self, a)) return self;
  67. exc = mrb_obj_clone(mrb, self);
  68. mrb_iv_set(mrb, exc, mrb_intern(mrb, "mesg"), a);
  69. return exc;
  70. }
  71. /*
  72. * call-seq:
  73. * exception.to_s -> string
  74. *
  75. * Returns exception's message (or the name of the exception if
  76. * no message is set).
  77. */
  78. static mrb_value
  79. exc_to_s(mrb_state *mrb, mrb_value exc)
  80. {
  81. mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern(mrb, "mesg"));
  82. if (mrb_nil_p(mesg)) return mrb_str_new2(mrb, mrb_obj_classname(mrb, exc));
  83. return mesg;
  84. }
  85. /*
  86. * call-seq:
  87. * exception.message -> string
  88. *
  89. * Returns the result of invoking <code>exception.to_s</code>.
  90. * Normally this returns the exception's message or name. By
  91. * supplying a to_str method, exceptions are agreeing to
  92. * be used where Strings are expected.
  93. */
  94. static mrb_value
  95. exc_message(mrb_state *mrb, mrb_value exc)
  96. {
  97. return mrb_funcall(mrb, exc, "to_s", 0);
  98. }
  99. /*
  100. * call-seq:
  101. * exception.inspect -> string
  102. *
  103. * Return this exception's class name an message
  104. */
  105. static mrb_value
  106. exc_inspect(mrb_state *mrb, mrb_value exc)
  107. {
  108. mrb_value str, mesg, file, line;
  109. mesg = mrb_attr_get(mrb, exc, mrb_intern(mrb, "mesg"));
  110. file = mrb_attr_get(mrb, exc, mrb_intern(mrb, "file"));
  111. line = mrb_attr_get(mrb, exc, mrb_intern(mrb, "line"));
  112. if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
  113. str = file;
  114. mrb_str_cat2(mrb, str, ":");
  115. mrb_str_append(mrb, str, line);
  116. mrb_str_cat2(mrb, str, ": ");
  117. if (RSTRING_LEN(mesg) > 0) {
  118. mrb_str_append(mrb, str, mesg);
  119. mrb_str_cat2(mrb, str, " (");
  120. }
  121. mrb_str_cat2(mrb, str, mrb_obj_classname(mrb, exc));
  122. if (RSTRING_LEN(mesg) > 0) {
  123. mrb_str_cat2(mrb, str, ")");
  124. }
  125. }
  126. else {
  127. str = mrb_str_new2(mrb, mrb_obj_classname(mrb, exc));
  128. if (RSTRING_LEN(mesg) > 0) {
  129. mrb_str_cat2(mrb, str, ": ");
  130. mrb_str_append(mrb, str, mesg);
  131. }
  132. }
  133. return str;
  134. }
  135. static mrb_value
  136. exc_equal(mrb_state *mrb, mrb_value exc)
  137. {
  138. mrb_value obj;
  139. mrb_value mesg;
  140. mrb_sym id_mesg = mrb_intern(mrb, "mesg");
  141. mrb_get_args(mrb, "o", &obj);
  142. if (mrb_obj_equal(mrb, exc, obj)) return mrb_true_value();
  143. if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) {
  144. if (mrb_respond_to(mrb, obj, mrb_intern(mrb, "message"))) {
  145. mesg = mrb_funcall(mrb, obj, "message", 0);
  146. }
  147. else
  148. return mrb_false_value();
  149. }
  150. else {
  151. mesg = mrb_attr_get(mrb, obj, id_mesg);
  152. }
  153. if (!mrb_equal(mrb, mrb_attr_get(mrb, exc, id_mesg), mesg))
  154. return mrb_false_value();
  155. return mrb_true_value();
  156. }
  157. static void
  158. exc_debug_info(mrb_state *mrb, struct RObject *exc)
  159. {
  160. mrb_callinfo *ci = mrb->ci;
  161. mrb_code *pc = ci->pc;
  162. ci--;
  163. while (ci >= mrb->cibase) {
  164. if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
  165. mrb_irep *irep = ci->proc->body.irep;
  166. if (irep->filename && irep->lines && irep->iseq <= pc && pc < irep->iseq + irep->ilen) {
  167. mrb_obj_iv_set(mrb, exc, mrb_intern(mrb, "file"), mrb_str_new_cstr(mrb, irep->filename));
  168. mrb_obj_iv_set(mrb, exc, mrb_intern(mrb, "line"), mrb_fixnum_value(irep->lines[pc - irep->iseq - 1]));
  169. return;
  170. }
  171. }
  172. pc = ci->pc;
  173. ci--;
  174. }
  175. }
  176. void
  177. mrb_exc_raise(mrb_state *mrb, mrb_value exc)
  178. {
  179. mrb->exc = (struct RObject*)mrb_object(exc);
  180. exc_debug_info(mrb, mrb->exc);
  181. if (!mrb->jmp) {
  182. abort();
  183. }
  184. longjmp(*(jmp_buf*)mrb->jmp, 1);
  185. }
  186. void
  187. mrb_raise(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
  188. {
  189. va_list args;
  190. char buf[256];
  191. int n;
  192. va_start(args, fmt);
  193. n = vsnprintf(buf, sizeof(buf), fmt, args);
  194. va_end(args);
  195. if (n < 0) {
  196. n = 0;
  197. }
  198. mrb_exc_raise(mrb, mrb_exc_new(mrb, c, buf, n));
  199. }
  200. void
  201. mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
  202. {
  203. mrb_value exc, argv[2];
  204. va_list args;
  205. char buf[256];
  206. int n;
  207. va_start(args, fmt);
  208. n = vsnprintf(buf, sizeof(buf), fmt, args);
  209. va_end(args);
  210. if (n < 0) {
  211. n = 0;
  212. }
  213. argv[0] = mrb_str_new(mrb, buf, n);
  214. argv[1] = mrb_symbol_value(id); /* ignore now */
  215. exc = mrb_class_new_instance(mrb, 1, argv, E_NAME_ERROR);
  216. mrb_exc_raise(mrb, exc);
  217. }
  218. mrb_value
  219. mrb_sprintf(mrb_state *mrb, const char *fmt, ...)
  220. {
  221. va_list args;
  222. char buf[256];
  223. int n;
  224. va_start(args, fmt);
  225. n = vsnprintf(buf, sizeof(buf), fmt, args);
  226. va_end(args);
  227. if (n < 0) {
  228. n = 0;
  229. }
  230. return mrb_str_new(mrb, buf, n);
  231. }
  232. void
  233. mrb_warn(const char *fmt, ...)
  234. {
  235. va_list args;
  236. va_start(args, fmt);
  237. printf("warning: ");
  238. vprintf(fmt, args);
  239. va_end(args);
  240. }
  241. void
  242. mrb_bug(const char *fmt, ...)
  243. {
  244. va_list args;
  245. va_start(args, fmt);
  246. printf("bug: ");
  247. vprintf(fmt, args);
  248. va_end(args);
  249. exit(EXIT_FAILURE);
  250. }
  251. static const char *
  252. mrb_strerrno(int err)
  253. {
  254. #define defined_error(name, num) if (err == num) return name;
  255. #define undefined_error(name)
  256. //#include "known_errors.inc"
  257. #undef defined_error
  258. #undef undefined_error
  259. return NULL;
  260. }
  261. void
  262. mrb_bug_errno(const char *mesg, int errno_arg)
  263. {
  264. if (errno_arg == 0)
  265. mrb_bug("%s: errno == 0 (NOERROR)", mesg);
  266. else {
  267. const char *errno_str = mrb_strerrno(errno_arg);
  268. if (errno_str)
  269. mrb_bug("%s: %s (%s)", mesg, strerror(errno_arg), errno_str);
  270. else
  271. mrb_bug("%s: %s (%d)", mesg, strerror(errno_arg), errno_arg);
  272. }
  273. }
  274. int
  275. sysexit_status(mrb_state *mrb, mrb_value err)
  276. {
  277. mrb_value st = mrb_iv_get(mrb, err, mrb_intern(mrb, "status"));
  278. return mrb_fixnum(st);
  279. }
  280. static void
  281. set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
  282. {
  283. mrb_funcall(mrb, info, "set_backtrace", 1, bt);
  284. }
  285. mrb_value
  286. make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr)
  287. {
  288. mrb_value mesg;
  289. int n;
  290. mesg = mrb_nil_value();
  291. switch (argc) {
  292. case 0:
  293. break;
  294. case 1:
  295. if (mrb_nil_p(argv[0]))
  296. break;
  297. if (isstr) {
  298. mesg = mrb_check_string_type(mrb, argv[0]);
  299. if (!mrb_nil_p(mesg)) {
  300. mesg = mrb_exc_new3(mrb, E_RUNTIME_ERROR, mesg);
  301. break;
  302. }
  303. }
  304. n = 0;
  305. goto exception_call;
  306. case 2:
  307. case 3:
  308. n = 1;
  309. exception_call:
  310. {
  311. mrb_sym exc = mrb_intern(mrb, "exception");
  312. if (mrb_respond_to(mrb, argv[0], exc)) {
  313. mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
  314. }
  315. else {
  316. /* undef */
  317. mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
  318. }
  319. }
  320. break;
  321. default:
  322. mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 0..3)", argc);
  323. break;
  324. }
  325. if (argc > 0) {
  326. if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
  327. mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
  328. if (argc > 2)
  329. set_backtrace(mrb, mesg, argv[2]);
  330. }
  331. return mesg;
  332. }
  333. mrb_value
  334. mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv)
  335. {
  336. return make_exception(mrb, argc, argv, TRUE);
  337. }
  338. void
  339. mrb_sys_fail(mrb_state *mrb, const char *mesg)
  340. {
  341. mrb_raise(mrb, E_RUNTIME_ERROR, "%s", mesg);
  342. }
  343. void
  344. mrb_init_exception(mrb_state *mrb)
  345. {
  346. struct RClass *e;
  347. mrb->eException_class = e = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
  348. mrb_define_class_method(mrb, e, "exception", mrb_instance_new, ARGS_ANY());
  349. mrb_define_method(mrb, e, "exception", exc_exception, ARGS_ANY());
  350. mrb_define_method(mrb, e, "initialize", exc_initialize, ARGS_ANY());
  351. mrb_define_method(mrb, e, "==", exc_equal, ARGS_REQ(1));
  352. mrb_define_method(mrb, e, "to_s", exc_to_s, ARGS_NONE());
  353. mrb_define_method(mrb, e, "message", exc_message, ARGS_NONE());
  354. mrb_define_method(mrb, e, "inspect", exc_inspect, ARGS_NONE());
  355. mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
  356. mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
  357. mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
  358. e = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
  359. mrb_define_class(mrb, "SyntaxError", e); /* 15.2.38 */
  360. }