source: EcnlProtoTool/trunk/mruby-1.2.0/src/error.c@ 270

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

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 11.3 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
48 if (mrb_get_args(mrb, "|o", &mesg) == 1) {
49 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
50 }
51 return exc;
52}
53
54/*
55 * Document-method: exception
56 *
57 * call-seq:
58 * exc.exception(string) -> an_exception or exc
59 *
60 * With no argument, or if the argument is the same as the receiver,
61 * return the receiver. Otherwise, create a new
62 * exception object of the same class as the receiver, but with a
63 * message equal to <code>string.to_str</code>.
64 *
65 */
66
67static mrb_value
68exc_exception(mrb_state *mrb, mrb_value self)
69{
70 mrb_value exc;
71 mrb_value a;
72 int argc;
73
74 argc = mrb_get_args(mrb, "|o", &a);
75 if (argc == 0) return self;
76 if (mrb_obj_equal(mrb, self, a)) return self;
77 exc = mrb_obj_clone(mrb, self);
78 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a);
79
80 return exc;
81}
82
83/*
84 * call-seq:
85 * exception.to_s -> string
86 *
87 * Returns exception's message (or the name of the exception if
88 * no message is set).
89 */
90
91static mrb_value
92exc_to_s(mrb_state *mrb, mrb_value exc)
93{
94 mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
95 struct RObject *p;
96
97 if (!mrb_string_p(mesg)) {
98 return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
99 }
100 p = mrb_obj_ptr(mesg);
101 if (!p->c) {
102 p->c = mrb->string_class;
103 }
104 return mesg;
105}
106
107/*
108 * call-seq:
109 * exception.message -> string
110 *
111 * Returns the result of invoking <code>exception.to_s</code>.
112 * Normally this returns the exception's message or name. By
113 * supplying a to_str method, exceptions are agreeing to
114 * be used where Strings are expected.
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
139 mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
140 file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
141 line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
142
143 append_mesg = !mrb_nil_p(mesg);
144 if (append_mesg) {
145 mesg = mrb_obj_as_string(mrb, mesg);
146 append_mesg = RSTRING_LEN(mesg) > 0;
147 }
148
149 if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
150 str = mrb_str_dup(mrb, file);
151 mrb_str_cat_lit(mrb, str, ":");
152 mrb_str_append(mrb, str, line);
153 mrb_str_cat_lit(mrb, str, ": ");
154 if (append_mesg) {
155 mrb_str_cat_str(mrb, str, mesg);
156 mrb_str_cat_lit(mrb, str, " (");
157 }
158 mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
159 if (append_mesg) {
160 mrb_str_cat_lit(mrb, str, ")");
161 }
162 }
163 else {
164 const char *cname = mrb_obj_classname(mrb, exc);
165 str = mrb_str_new_cstr(mrb, cname);
166 mrb_str_cat_lit(mrb, str, ": ");
167 if (append_mesg) {
168 mrb_str_cat_str(mrb, str, mesg);
169 }
170 else {
171 mrb_str_cat_cstr(mrb, str, cname);
172 }
173 }
174 return str;
175}
176
177
178static void
179exc_debug_info(mrb_state *mrb, struct RObject *exc)
180{
181 mrb_callinfo *ci = mrb->c->ci;
182 mrb_code *pc = ci->pc;
183
184 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value((mrb_int)(ci - mrb->c->cibase)));
185 while (ci >= mrb->c->cibase) {
186 mrb_code *err = ci->err;
187
188 if (!err && pc) err = pc - 1;
189 if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
190 mrb_irep *irep = ci->proc->body.irep;
191
192 int32_t const line = mrb_debug_get_line(irep, (uint32_t)(err - irep->iseq));
193 char const* file = mrb_debug_get_filename(irep, (uint32_t)(err - irep->iseq));
194 if (line != -1 && file) {
195 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
196 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
197 return;
198 }
199 }
200 pc = ci->pc;
201 ci--;
202 }
203}
204
205MRB_API mrb_noreturn void
206mrb_exc_raise(mrb_state *mrb, mrb_value exc)
207{
208 mrb->exc = mrb_obj_ptr(exc);
209 if (!mrb->gc.out_of_memory) {
210 exc_debug_info(mrb, mrb->exc);
211 }
212 if (!mrb->jmp) {
213 mrb_p(mrb, exc);
214 abort();
215 }
216 MRB_THROW(mrb->jmp);
217}
218
219MRB_API mrb_noreturn void
220mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
221{
222 mrb_value mesg;
223 mesg = mrb_str_new_cstr(mrb, msg);
224 mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
225}
226
227MRB_API mrb_value
228mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
229{
230 const char *p = format;
231 const char *b = p;
232 ptrdiff_t size;
233 mrb_value ary = mrb_ary_new_capa(mrb, 4);
234
235 while (*p) {
236 const char c = *p++;
237
238 if (c == '%') {
239 if (*p == 'S') {
240 size = p - b - 1;
241 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
242 mrb_ary_push(mrb, ary, va_arg(ap, mrb_value));
243 b = p + 1;
244 }
245 }
246 else if (c == '\\') {
247 if (*p) {
248 size = p - b - 1;
249 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
250 mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
251 b = ++p;
252 }
253 else {
254 break;
255 }
256 }
257 }
258 if (b == format) {
259 return mrb_str_new_cstr(mrb, format);
260 }
261 else {
262 size = p - b;
263 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
264 return mrb_ary_join(mrb, ary, mrb_str_new(mrb, NULL, 0));
265 }
266}
267
268MRB_API mrb_value
269mrb_format(mrb_state *mrb, const char *format, ...)
270{
271 va_list ap;
272 mrb_value str;
273
274 va_start(ap, format);
275 str = mrb_vformat(mrb, format, ap);
276 va_end(ap);
277
278 return str;
279}
280
281MRB_API mrb_noreturn void
282mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
283{
284 va_list args;
285 mrb_value mesg;
286
287 va_start(args, fmt);
288 mesg = mrb_vformat(mrb, fmt, args);
289 va_end(args);
290 mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg));
291}
292
293MRB_API mrb_noreturn void
294mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
295{
296 mrb_value exc;
297 mrb_value argv[2];
298 va_list args;
299
300 va_start(args, fmt);
301 argv[0] = mrb_vformat(mrb, fmt, args);
302 va_end(args);
303
304 argv[1] = mrb_symbol_value(id);
305 exc = mrb_obj_new(mrb, E_NAME_ERROR, 2, argv);
306 mrb_exc_raise(mrb, exc);
307}
308
309MRB_API void
310mrb_warn(mrb_state *mrb, const char *fmt, ...)
311{
312#ifndef MRB_DISABLE_STDIO
313 va_list ap;
314 mrb_value str;
315
316 va_start(ap, fmt);
317 str = mrb_vformat(mrb, fmt, ap);
318 fputs("warning: ", stderr);
319 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
320 va_end(ap);
321#endif
322}
323
324MRB_API mrb_noreturn void
325mrb_bug(mrb_state *mrb, const char *fmt, ...)
326{
327#ifndef MRB_DISABLE_STDIO
328 va_list ap;
329 mrb_value str;
330
331 va_start(ap, fmt);
332 str = mrb_vformat(mrb, fmt, ap);
333 fputs("bug: ", stderr);
334 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
335 va_end(ap);
336#endif
337 exit(EXIT_FAILURE);
338}
339
340static void
341set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
342{
343 mrb_funcall(mrb, info, "set_backtrace", 1, bt);
344}
345
346static mrb_value
347make_exception(mrb_state *mrb, int argc, const mrb_value *argv, mrb_bool isstr)
348{
349 mrb_value mesg;
350 int n;
351
352 mesg = mrb_nil_value();
353 switch (argc) {
354 case 0:
355 break;
356 case 1:
357 if (mrb_nil_p(argv[0]))
358 break;
359 if (isstr) {
360 mesg = mrb_check_string_type(mrb, argv[0]);
361 if (!mrb_nil_p(mesg)) {
362 mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mesg);
363 break;
364 }
365 }
366 n = 0;
367 goto exception_call;
368
369 case 2:
370 case 3:
371 n = 1;
372exception_call:
373 {
374 mrb_sym exc = mrb_intern_lit(mrb, "exception");
375 if (mrb_respond_to(mrb, argv[0], exc)) {
376 mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
377 }
378 else {
379 /* undef */
380 mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
381 }
382 }
383
384 break;
385 default:
386 mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
387 break;
388 }
389 if (argc > 0) {
390 if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
391 mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
392 if (argc > 2)
393 set_backtrace(mrb, mesg, argv[2]);
394 }
395
396 return mesg;
397}
398
399MRB_API mrb_value
400mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv)
401{
402 return make_exception(mrb, argc, argv, TRUE);
403}
404
405MRB_API void
406mrb_sys_fail(mrb_state *mrb, const char *mesg)
407{
408 struct RClass *sce;
409 mrb_int no;
410
411 no = (mrb_int)errno;
412 if (mrb_class_defined(mrb, "SystemCallError")) {
413 sce = mrb_class_get(mrb, "SystemCallError");
414 if (mesg != NULL) {
415 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg));
416 }
417 else {
418 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no));
419 }
420 }
421 else {
422 mrb_raise(mrb, E_RUNTIME_ERROR, mesg);
423 }
424}
425
426MRB_API mrb_noreturn void
427mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...)
428{
429 mrb_value exc;
430 va_list ap;
431
432 va_start(ap, fmt);
433 exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3,
434 mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id), args);
435 va_end(ap);
436 mrb_exc_raise(mrb, exc);
437}
438
439void
440mrb_init_exception(mrb_state *mrb)
441{
442 struct RClass *exception, *runtime_error, *script_error;
443
444 mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
445 MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
446 mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY());
447 mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY());
448 mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY());
449 mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE());
450 mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE());
451 mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE());
452 mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE());
453
454 mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
455 runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
456 mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory"));
457 script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
458 mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */
459 mrb_define_class(mrb, "SystemStackError", exception);
460}
Note: See TracBrowser for help on using the repository browser.