Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
error.c
Go to the documentation of this file.
1 /*
2 ** error.c - Exception class
3 **
4 ** See Copyright Notice in mruby.h
5 */
6 
7 #include <errno.h>
8 #include <stdarg.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "mruby.h"
12 #include "mruby/array.h"
13 #include "mruby/class.h"
14 #include "mruby/irep.h"
15 #include "mruby/proc.h"
16 #include "mruby/string.h"
17 #include "mruby/variable.h"
18 #include "mruby/debug.h"
19 #include "error.h"
20 
22 mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
23 {
24  return mrb_funcall(mrb, mrb_obj_value(c), "new", 1, mrb_str_new(mrb, ptr, len));
25 }
26 
28 mrb_exc_new3(mrb_state *mrb, struct RClass* c, mrb_value str)
29 {
30  str = mrb_str_to_str(mrb, str);
31  return mrb_funcall(mrb, mrb_obj_value(c), "new", 1, str);
32 }
33 
34 /*
35  * call-seq:
36  * Exception.new(msg = nil) -> exception
37  *
38  * Construct a new Exception object, optionally passing in
39  * a message.
40  */
41 
42 static mrb_value
43 exc_initialize(mrb_state *mrb, mrb_value exc)
44 {
45  mrb_value mesg;
46 
47  if (mrb_get_args(mrb, "|o", &mesg) == 1) {
48  mrb_iv_set(mrb, exc, mrb_intern2(mrb, "mesg", 4), mesg);
49  }
50  return exc;
51 }
52 
53 /*
54  * Document-method: exception
55  *
56  * call-seq:
57  * exc.exception(string) -> an_exception or exc
58  *
59  * With no argument, or if the argument is the same as the receiver,
60  * return the receiver. Otherwise, create a new
61  * exception object of the same class as the receiver, but with a
62  * message equal to <code>string.to_str</code>.
63  *
64  */
65 
66 static mrb_value
67 exc_exception(mrb_state *mrb, mrb_value self)
68 {
69  mrb_value exc;
70  mrb_value a;
71  int argc;
72 
73  argc = mrb_get_args(mrb, "|o", &a);
74  if (argc == 0) return self;
75  if (mrb_obj_equal(mrb, self, a)) return self;
76  exc = mrb_obj_clone(mrb, self);
77  mrb_iv_set(mrb, exc, mrb_intern2(mrb, "mesg", 4), a);
78 
79  return exc;
80 }
81 
82 /*
83  * call-seq:
84  * exception.to_s -> string
85  *
86  * Returns exception's message (or the name of the exception if
87  * no message is set).
88  */
89 
90 static mrb_value
91 exc_to_s(mrb_state *mrb, mrb_value exc)
92 {
93  mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "mesg", 4));
94 
95  if (mrb_nil_p(mesg)) return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
96  return mesg;
97 }
98 
99 /*
100  * call-seq:
101  * exception.message -> string
102  *
103  * Returns the result of invoking <code>exception.to_s</code>.
104  * Normally this returns the exception's message or name. By
105  * supplying a to_str method, exceptions are agreeing to
106  * be used where Strings are expected.
107  */
108 
109 static mrb_value
110 exc_message(mrb_state *mrb, mrb_value exc)
111 {
112  return mrb_funcall(mrb, exc, "to_s", 0);
113 }
114 
115 /*
116  * call-seq:
117  * exception.inspect -> string
118  *
119  * Return this exception's class name an message
120  */
121 
122 static mrb_value
123 exc_inspect(mrb_state *mrb, mrb_value exc)
124 {
125  mrb_value str, mesg, file, line;
126 
127  mesg = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "mesg", 4));
128  file = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "file", 4));
129  line = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "line", 4));
130 
131  if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
132  str = file;
133  mrb_str_cat(mrb, str, ":", 1);
134  mrb_str_append(mrb, str, line);
135  mrb_str_cat(mrb, str, ": ", 2);
136  if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
137  mrb_str_append(mrb, str, mesg);
138  mrb_str_cat(mrb, str, " (", 2);
139  }
140  mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
141  if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
142  mrb_str_cat(mrb, str, ")", 1);
143  }
144  }
145  else {
146  str = mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
147  if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
148  mrb_str_cat(mrb, str, ": ", 2);
149  mrb_str_append(mrb, str, mesg);
150  }
151  else {
152  mrb_str_cat(mrb, str, ": ", 2);
153  mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
154  }
155  }
156  return str;
157 }
158 
159 
160 static mrb_value
161 exc_equal(mrb_state *mrb, mrb_value exc)
162 {
163  mrb_value obj;
164  mrb_value mesg;
165  mrb_bool equal_p;
166  mrb_sym id_mesg = mrb_intern2(mrb, "mesg", 4);
167 
168  mrb_get_args(mrb, "o", &obj);
169  if (mrb_obj_equal(mrb, exc, obj)) {
170  equal_p = 1;
171  }
172  else {
173  if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) {
174  if (mrb_respond_to(mrb, obj, mrb_intern2(mrb, "message", 7))) {
175  mesg = mrb_funcall(mrb, obj, "message", 0);
176  }
177  else
178  return mrb_false_value();
179  }
180  else {
181  mesg = mrb_attr_get(mrb, obj, id_mesg);
182  }
183 
184  equal_p = mrb_equal(mrb, mrb_attr_get(mrb, exc, id_mesg), mesg);
185  }
186 
187  return mrb_bool_value(equal_p);
188 }
189 
190 static void
191 exc_debug_info(mrb_state *mrb, struct RObject *exc)
192 {
193  mrb_callinfo *ci = mrb->c->ci;
194  mrb_code *pc = ci->pc;
195 
196  mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "ciidx", 5), mrb_fixnum_value(ci - mrb->c->cibase));
197  ci--;
198  while (ci >= mrb->c->cibase) {
199  if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
200  mrb_irep *irep = ci->proc->body.irep;
201 
202  int32_t const line = mrb_debug_get_line(irep, pc - irep->iseq - 1);
203  char const* file = mrb_debug_get_filename(irep, pc - irep->iseq - 1);
204  if(line != -1 && file) {
205  mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "file", 4), mrb_str_new_cstr(mrb, file));
206  mrb_obj_iv_set(mrb, exc, mrb_intern2(mrb, "line", 4), mrb_fixnum_value(line));
207  return;
208  }
209  }
210  pc = ci->pc;
211  ci--;
212  }
213 }
214 
215 void
217 {
218  mrb->exc = mrb_obj_ptr(exc);
219  exc_debug_info(mrb, mrb->exc);
220  if (!mrb->jmp) {
221  mrb_p(mrb, exc);
222  abort();
223  }
224  mrb_longjmp(mrb);
225 }
226 
227 void
228 mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
229 {
230  mrb_value mesg;
231  mesg = mrb_str_new_cstr(mrb, msg);
232  mrb_exc_raise(mrb, mrb_exc_new3(mrb, c, mesg));
233 }
234 
235 mrb_value
236 mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
237 {
238  const char *p = format;
239  const char *b = p;
240  ptrdiff_t size;
241  mrb_value ary = mrb_ary_new_capa(mrb, 4);
242 
243  while (*p) {
244  const char c = *p++;
245 
246  if (c == '%') {
247  if (*p == 'S') {
248  size = p - b - 1;
249  mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
250  mrb_ary_push(mrb, ary, va_arg(ap, mrb_value));
251  b = p + 1;
252  }
253  }
254  else if (c == '\\') {
255  if (*p) {
256  size = p - b - 1;
257  mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
258  mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
259  b = ++p;
260  }
261  else {
262  break;
263  }
264  }
265  }
266  if (b == format) {
267  return mrb_str_new_cstr(mrb, format);
268  }
269  else {
270  size = p - b;
271  mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
272  return mrb_ary_join(mrb, ary, mrb_str_new(mrb,NULL,0));
273  }
274 }
275 
276 mrb_value
277 mrb_format(mrb_state *mrb, const char *format, ...)
278 {
279  va_list ap;
280  mrb_value str;
281 
282  va_start(ap, format);
283  str = mrb_vformat(mrb, format, ap);
284  va_end(ap);
285 
286  return str;
287 }
288 
289 void
290 mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
291 {
292  va_list args;
293  mrb_value mesg;
294 
295  va_start(args, fmt);
296  mesg = mrb_vformat(mrb, fmt, args);
297  va_end(args);
298  mrb_exc_raise(mrb, mrb_exc_new3(mrb, c, mesg));
299 }
300 
301 void
302 mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
303 {
304  mrb_value exc;
305  mrb_value argv[2];
306  va_list args;
307 
308  va_start(args, fmt);
309  argv[0] = mrb_vformat(mrb, fmt, args);
310  va_end(args);
311 
312  argv[1] = mrb_symbol_value(id);
313  exc = mrb_obj_new(mrb, E_NAME_ERROR, 2, argv);
314  mrb_exc_raise(mrb, exc);
315 }
316 
317 void
318 mrb_warn(mrb_state *mrb, const char *fmt, ...)
319 {
320 #ifdef ENABLE_STDIO
321  va_list ap;
322  mrb_value str;
323 
324  va_start(ap, fmt);
325  str = mrb_vformat(mrb, fmt, ap);
326  fputs("warning: ", stderr);
327  fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
328  va_end(ap);
329 #endif
330 }
331 
332 void
333 mrb_bug(mrb_state *mrb, const char *fmt, ...)
334 {
335 #ifdef ENABLE_STDIO
336  va_list ap;
337  mrb_value str;
338 
339  va_start(ap, fmt);
340  str = mrb_vformat(mrb, fmt, ap);
341  fputs("bug: ", stderr);
342  fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
343  va_end(ap);
344 #endif
345  exit(EXIT_FAILURE);
346 }
347 
348 int
350 {
351  mrb_value st = mrb_iv_get(mrb, err, mrb_intern2(mrb, "status", 6));
352  return mrb_fixnum(st);
353 }
354 
355 static void
356 set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
357 {
358  mrb_funcall(mrb, info, "set_backtrace", 1, bt);
359 }
360 
361 mrb_value
362 make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr)
363 {
364  mrb_value mesg;
365  int n;
366 
367  mesg = mrb_nil_value();
368  switch (argc) {
369  case 0:
370  break;
371  case 1:
372  if (mrb_nil_p(argv[0]))
373  break;
374  if (isstr) {
375  mesg = mrb_check_string_type(mrb, argv[0]);
376  if (!mrb_nil_p(mesg)) {
377  mesg = mrb_exc_new3(mrb, E_RUNTIME_ERROR, mesg);
378  break;
379  }
380  }
381  n = 0;
382  goto exception_call;
383 
384  case 2:
385  case 3:
386  n = 1;
387 exception_call:
388  {
389  mrb_sym exc = mrb_intern2(mrb, "exception", 9);
390  if (mrb_respond_to(mrb, argv[0], exc)) {
391  mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
392  }
393  else {
394  /* undef */
395  mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
396  }
397  }
398 
399  break;
400  default:
401  mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
402  break;
403  }
404  if (argc > 0) {
405  if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
406  mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
407  if (argc > 2)
408  set_backtrace(mrb, mesg, argv[2]);
409  }
410 
411  return mesg;
412 }
413 
414 mrb_value
415 mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv)
416 {
417  return make_exception(mrb, argc, argv, TRUE);
418 }
419 
420 void
421 mrb_sys_fail(mrb_state *mrb, const char *mesg)
422 {
423  struct RClass *sce;
424  mrb_int no;
425 
426  no = (mrb_int)errno;
427  if (mrb_class_defined(mrb, "SystemCallError")) {
428  sce = mrb_class_get(mrb, "SystemCallError");
429  if (mesg != NULL) {
430  mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg));
431  }
432  else {
433  mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no));
434  }
435  }
436  else {
437  mrb_raise(mrb, E_RUNTIME_ERROR, mesg);
438  }
439 }
440 
442 
443 void
445 {
446  struct RClass *e;
447 
448  mrb->eException_class = e = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
449  mrb_define_class_method(mrb, e, "exception", mrb_instance_new, MRB_ARGS_ANY());
450  mrb_define_method(mrb, e, "exception", exc_exception, MRB_ARGS_ANY());
451  mrb_define_method(mrb, e, "initialize", exc_initialize, MRB_ARGS_ANY());
452  mrb_define_method(mrb, e, "==", exc_equal, MRB_ARGS_REQ(1));
453  mrb_define_method(mrb, e, "to_s", exc_to_s, MRB_ARGS_NONE());
454  mrb_define_method(mrb, e, "message", exc_message, MRB_ARGS_NONE());
455  mrb_define_method(mrb, e, "inspect", exc_inspect, MRB_ARGS_NONE());
456  mrb_define_method(mrb, e, "backtrace", mrb_get_backtrace, MRB_ARGS_NONE());
457 
458  mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
459  mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
460  e = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
461  mrb_define_class(mrb, "SyntaxError", e); /* 15.2.38 */
462 }