source: EcnlProtoTool/trunk/mruby-1.3.0/src/error.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 12.2 KB
Line 
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 <mruby.h>
11#include <mruby/array.h>
12#include <mruby/irep.h>
13#include <mruby/proc.h>
14#include <mruby/string.h>
15#include <mruby/variable.h>
16#include <mruby/debug.h>
17#include <mruby/error.h>
18#include <mruby/class.h>
19#include <mruby/throw.h>
20
21MRB_API mrb_value
22mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
23{
24 mrb_value arg = mrb_str_new(mrb, ptr, len);
25 return mrb_obj_new(mrb, c, 1, &arg);
26}
27
28MRB_API mrb_value
29mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
30{
31 str = mrb_str_to_str(mrb, str);
32 return mrb_obj_new(mrb, c, 1, &str);
33}
34
35/*
36 * call-seq:
37 * Exception.new(msg = nil) -> exception
38 *
39 * Construct a new Exception object, optionally passing in
40 * a message.
41 */
42
43static mrb_value
44exc_initialize(mrb_state *mrb, mrb_value exc)
45{
46 mrb_value mesg;
47 mrb_int argc;
48 mrb_value *argv;
49
50 if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) {
51 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
52 }
53 return exc;
54}
55
56/*
57 * Document-method: exception
58 *
59 * call-seq:
60 * exc.exception(string) -> an_exception or exc
61 *
62 * With no argument, or if the argument is the same as the receiver,
63 * return the receiver. Otherwise, create a new
64 * exception object of the same class as the receiver, but with a
65 * message equal to <code>string</code>.
66 *
67 */
68
69static mrb_value
70exc_exception(mrb_state *mrb, mrb_value self)
71{
72 mrb_value exc;
73 mrb_value a;
74 int argc;
75
76 argc = mrb_get_args(mrb, "|o", &a);
77 if (argc == 0) return self;
78 if (mrb_obj_equal(mrb, self, a)) return self;
79 exc = mrb_obj_clone(mrb, self);
80 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a);
81
82 return exc;
83}
84
85/*
86 * call-seq:
87 * exception.to_s -> string
88 *
89 * Returns exception's message (or the name of the exception if
90 * no message is set).
91 */
92
93static mrb_value
94exc_to_s(mrb_state *mrb, mrb_value exc)
95{
96 mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
97 struct RObject *p;
98
99 if (!mrb_string_p(mesg)) {
100 return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
101 }
102 p = mrb_obj_ptr(mesg);
103 if (!p->c) {
104 p->c = mrb->string_class;
105 }
106 return mesg;
107}
108
109/*
110 * call-seq:
111 * exception.message -> string
112 *
113 * Returns the result of invoking <code>exception.to_s</code>.
114 * Normally this returns the exception's message or name.
115 */
116
117static mrb_value
118exc_message(mrb_state *mrb, mrb_value exc)
119{
120 return mrb_funcall(mrb, exc, "to_s", 0);
121}
122
123/*
124 * call-seq:
125 * exception.inspect -> string
126 *
127 * Returns this exception's file name, line number,
128 * message and class name.
129 * If file name or line number is not set,
130 * returns message and class name.
131 */
132
133static mrb_value
134exc_inspect(mrb_state *mrb, mrb_value exc)
135{
136 mrb_value str, mesg, file, line;
137 mrb_bool append_mesg;
138 const char *cname;
139
140 mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
141 file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
142 line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
143
144 append_mesg = !mrb_nil_p(mesg);
145 if (append_mesg) {
146 mesg = mrb_obj_as_string(mrb, mesg);
147 append_mesg = RSTRING_LEN(mesg) > 0;
148 }
149
150 cname = mrb_obj_classname(mrb, exc);
151 str = mrb_str_new_cstr(mrb, cname);
152 if (mrb_string_p(file) && mrb_fixnum_p(line)) {
153 if (append_mesg) {
154 str = mrb_format(mrb, "%S:%S:%S (%S)", file, line, mesg, str);
155 }
156 else {
157 str = mrb_format(mrb, "%S:%S:%S", file, line, str);
158 }
159 }
160 else if (append_mesg) {
161 str = mrb_format(mrb, "%S:%S", str, mesg);
162 }
163 return str;
164}
165
166void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc);
167
168static void
169set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
170{
171 if (!mrb_array_p(backtrace)) {
172 type_err:
173 mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String");
174 }
175 else {
176 const mrb_value *p = RARRAY_PTR(backtrace);
177 const mrb_value *pend = p + RARRAY_LEN(backtrace);
178
179 while (p < pend) {
180 if (!mrb_string_p(*p)) goto type_err;
181 p++;
182 }
183 }
184 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
185}
186
187static mrb_value
188exc_set_backtrace(mrb_state *mrb, mrb_value exc)
189{
190 mrb_value backtrace;
191
192 mrb_get_args(mrb, "o", &backtrace);
193 set_backtrace(mrb, exc, backtrace);
194 return backtrace;
195}
196
197static void
198exc_debug_info(mrb_state *mrb, struct RObject *exc)
199{
200 mrb_callinfo *ci = mrb->c->ci;
201 mrb_code *pc = ci->pc;
202
203 while (ci >= mrb->c->cibase) {
204 mrb_code *err = ci->err;
205
206 if (!err && pc) err = pc - 1;
207 if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
208 mrb_irep *irep = ci->proc->body.irep;
209
210 int32_t const line = mrb_debug_get_line(irep, (uint32_t)(err - irep->iseq));
211 char const* file = mrb_debug_get_filename(irep, (uint32_t)(err - irep->iseq));
212 if (line != -1 && file) {
213 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
214 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
215 return;
216 }
217 }
218 pc = ci->pc;
219 ci--;
220 }
221}
222
223void
224mrb_exc_set(mrb_state *mrb, mrb_value exc)
225{
226 if (mrb_nil_p(exc)) {
227 mrb->exc = 0;
228 }
229 else {
230 mrb->exc = mrb_obj_ptr(exc);
231 if (!mrb->gc.out_of_memory) {
232 exc_debug_info(mrb, mrb->exc);
233 mrb_keep_backtrace(mrb, exc);
234 }
235 }
236}
237
238MRB_API mrb_noreturn void
239mrb_exc_raise(mrb_state *mrb, mrb_value exc)
240{
241 if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) {
242 mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
243 }
244 mrb_exc_set(mrb, exc);
245 if (!mrb->jmp) {
246 mrb_p(mrb, exc);
247 abort();
248 }
249 MRB_THROW(mrb->jmp);
250}
251
252MRB_API mrb_noreturn void
253mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
254{
255 mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg)));
256}
257
258MRB_API mrb_value
259mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
260{
261 const char *p = format;
262 const char *b = p;
263 ptrdiff_t size;
264 mrb_value ary = mrb_ary_new_capa(mrb, 4);
265 int ai = mrb_gc_arena_save(mrb);
266
267 while (*p) {
268 const char c = *p++;
269
270 if (c == '%') {
271 if (*p == 'S') {
272 size = p - b - 1;
273 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
274 mrb_ary_push(mrb, ary, va_arg(ap, mrb_value));
275 b = p + 1;
276 }
277 }
278 else if (c == '\\') {
279 if (*p) {
280 size = p - b - 1;
281 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
282 mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
283 b = ++p;
284 }
285 else {
286 break;
287 }
288 }
289 mrb_gc_arena_restore(mrb, ai);
290 }
291 if (b == format) {
292 return mrb_str_new_cstr(mrb, format);
293 }
294 else {
295 size = p - b;
296 if (size > 0) {
297 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
298 mrb_gc_arena_restore(mrb, ai);
299 }
300 return mrb_ary_join(mrb, ary, mrb_nil_value());
301 }
302}
303
304MRB_API mrb_value
305mrb_format(mrb_state *mrb, const char *format, ...)
306{
307 va_list ap;
308 mrb_value str;
309
310 va_start(ap, format);
311 str = mrb_vformat(mrb, format, ap);
312 va_end(ap);
313
314 return str;
315}
316
317static mrb_noreturn void
318raise_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap, int argc, mrb_value *argv)
319{
320 mrb_value mesg;
321
322 mesg = mrb_vformat(mrb, fmt, ap);
323 if (argv == NULL) {
324 argv = &mesg;
325 }
326 else {
327 argv[0] = mesg;
328 }
329 mrb_exc_raise(mrb, mrb_obj_new(mrb, c, argc+1, argv));
330}
331
332MRB_API mrb_noreturn void
333mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
334{
335 va_list args;
336
337 va_start(args, fmt);
338 raise_va(mrb, c, fmt, args, 0, NULL);
339 va_end(args);
340}
341
342MRB_API mrb_noreturn void
343mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
344{
345 mrb_value argv[2];
346 va_list args;
347
348 va_start(args, fmt);
349 argv[1] = mrb_symbol_value(id);
350 raise_va(mrb, E_NAME_ERROR, fmt, args, 1, argv);
351 va_end(args);
352}
353
354MRB_API void
355mrb_warn(mrb_state *mrb, const char *fmt, ...)
356{
357#ifndef MRB_DISABLE_STDIO
358 va_list ap;
359 mrb_value str;
360
361 va_start(ap, fmt);
362 str = mrb_vformat(mrb, fmt, ap);
363 fputs("warning: ", stderr);
364 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
365 va_end(ap);
366#endif
367}
368
369MRB_API mrb_noreturn void
370mrb_bug(mrb_state *mrb, const char *fmt, ...)
371{
372#ifndef MRB_DISABLE_STDIO
373 va_list ap;
374 mrb_value str;
375
376 va_start(ap, fmt);
377 str = mrb_vformat(mrb, fmt, ap);
378 fputs("bug: ", stderr);
379 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
380 va_end(ap);
381#endif
382 exit(EXIT_FAILURE);
383}
384
385MRB_API mrb_value
386mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv)
387{
388 mrb_value mesg;
389 int n;
390
391 mesg = mrb_nil_value();
392 switch (argc) {
393 case 0:
394 break;
395 case 1:
396 if (mrb_nil_p(argv[0]))
397 break;
398 if (mrb_string_p(argv[0])) {
399 mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, argv[0]);
400 break;
401 }
402 n = 0;
403 goto exception_call;
404
405 case 2:
406 case 3:
407 n = 1;
408exception_call:
409 {
410 mrb_sym exc = mrb_intern_lit(mrb, "exception");
411 if (mrb_respond_to(mrb, argv[0], exc)) {
412 mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
413 }
414 else {
415 /* undef */
416 mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
417 }
418 }
419
420 break;
421 default:
422 mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
423 break;
424 }
425 if (argc > 0) {
426 if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
427 mrb_raise(mrb, mrb->eException_class, "exception object expected");
428 if (argc > 2)
429 set_backtrace(mrb, mesg, argv[2]);
430 }
431
432 return mesg;
433}
434
435MRB_API void
436mrb_sys_fail(mrb_state *mrb, const char *mesg)
437{
438 struct RClass *sce;
439 mrb_int no;
440
441 no = (mrb_int)errno;
442 if (mrb_class_defined(mrb, "SystemCallError")) {
443 sce = mrb_class_get(mrb, "SystemCallError");
444 if (mesg != NULL) {
445 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg));
446 }
447 else {
448 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no));
449 }
450 }
451 else {
452 mrb_raise(mrb, E_RUNTIME_ERROR, mesg);
453 }
454}
455
456MRB_API mrb_noreturn void
457mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...)
458{
459 mrb_value exc;
460 mrb_value argv[3];
461 va_list ap;
462
463 va_start(ap, fmt);
464 argv[0] = mrb_vformat(mrb, fmt, ap);
465 argv[1] = mrb_symbol_value(id);
466 argv[2] = args;
467 va_end(ap);
468 exc = mrb_obj_new(mrb, E_NOMETHOD_ERROR, 3, argv);
469 mrb_exc_raise(mrb, exc);
470}
471
472void
473mrb_init_exception(mrb_state *mrb)
474{
475 struct RClass *exception, *script_error, *stack_error, *nomem_error;
476
477 mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
478 MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
479 mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY());
480 mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY());
481 mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY());
482 mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
483 mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
484 mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
485 mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
486 mrb_define_method(mrb, exception, "set_backtrace", exc_set_backtrace, MRB_ARGS_REQ(1));
487
488 mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
489 mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
490 script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
491 mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
492 stack_error = mrb_define_class(mrb, "SystemStackError", exception);
493 mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep"));
494
495 nomem_error = mrb_define_class(mrb, "NoMemoryError", exception);
496 mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "Out of memory"));
497#ifdef MRB_GC_FIXED_ARENA
498 mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "arena overflow error"));
499#endif
500}
Note: See TracBrowser for help on using the repository browser.