Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 418 lines (363 sloc) 9.869 kB
8354436 @mimaki add file header
mimaki authored
1 /*
2 ** error.c - Exception class
4ec6d41 rm whitespace
roco authored
3 **
8354436 @mimaki add file header
mimaki authored
4 ** See Copyright Notice in mruby.h
5 */
6
e0d6430 @mimaki add mruby sources
mimaki authored
7 #include "mruby.h"
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <setjmp.h>
c9fe903 @matz now segmented list can be used as instance variable tables by -DMRB_U…
matz authored
11 #include <string.h>
e0d6430 @mimaki add mruby sources
mimaki authored
12 #include "error.h"
2fc1b8a @matz mv variable.h to mruby/variable.h
matz authored
13 #include "mruby/variable.h"
e0d6430 @mimaki add mruby sources
mimaki authored
14 #include "mruby/string.h"
15 #include "mruby/class.h"
f114916 @matz source position added to exception representation
matz authored
16 #include "mruby/proc.h"
17 #include "mruby/irep.h"
e0d6430 @mimaki add mruby sources
mimaki authored
18
19 #define warn_printf printf
20
21 mrb_value
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
27 mrb_value
28 mrb_exc_new3(mrb_state *mrb, struct RClass* c, mrb_value str)
29 {
30 //StringValue(str);
31 mrb_string_value(mrb, &str);
32 return mrb_funcall(mrb, mrb_obj_value(c), "new", 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
43 static mrb_value
44 exc_initialize(mrb_state *mrb, mrb_value exc)
45 {
46 mrb_value mesg;
47
fae483f @matz the argument for Exception.new is optinal
matz authored
48 if (mrb_get_args(mrb, "|o", &mesg) == 1) {
49 mrb_iv_set(mrb, exc, mrb_intern(mrb, "mesg"), mesg);
50 }
e0d6430 @mimaki add mruby sources
mimaki authored
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
67 static mrb_value
68 exc_exception(mrb_state *mrb, mrb_value self)
69 {
70 mrb_value exc;
8f9b958 @matz raise should initialize Exception object
matz authored
71 mrb_value a;
e0d6430 @mimaki add mruby sources
mimaki authored
72 int argc;
73
8f9b958 @matz raise should initialize Exception object
matz authored
74 argc = mrb_get_args(mrb, "|o", &a);
e0d6430 @mimaki add mruby sources
mimaki authored
75 if (argc == 0) return self;
8f9b958 @matz raise should initialize Exception object
matz authored
76 if (mrb_obj_equal(mrb, self, a)) return self;
e0d6430 @mimaki add mruby sources
mimaki authored
77 exc = mrb_obj_clone(mrb, self);
8f9b958 @matz raise should initialize Exception object
matz authored
78 mrb_iv_set(mrb, exc, mrb_intern(mrb, "mesg"), a);
e0d6430 @mimaki add mruby sources
mimaki authored
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
91 static mrb_value
92 exc_to_s(mrb_state *mrb, mrb_value exc)
93 {
94 mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern(mrb, "mesg"));
95
96 if (mrb_nil_p(mesg)) return mrb_str_new2(mrb, mrb_obj_classname(mrb, exc));
97 return mesg;
98 }
99
100 /*
101 * call-seq:
102 * exception.message -> string
103 *
104 * Returns the result of invoking <code>exception.to_s</code>.
105 * Normally this returns the exception's message or name. By
106 * supplying a to_str method, exceptions are agreeing to
107 * be used where Strings are expected.
108 */
109
110 static mrb_value
111 exc_message(mrb_state *mrb, mrb_value exc)
112 {
113 return mrb_funcall(mrb, exc, "to_s", 0);
114 }
115
116 /*
117 * call-seq:
118 * exception.inspect -> string
119 *
120 * Return this exception's class name an message
121 */
122
123 static mrb_value
124 exc_inspect(mrb_state *mrb, mrb_value exc)
125 {
f114916 @matz source position added to exception representation
matz authored
126 mrb_value str, mesg, file, line;
127
128 mesg = mrb_attr_get(mrb, exc, mrb_intern(mrb, "mesg"));
129 file = mrb_attr_get(mrb, exc, mrb_intern(mrb, "file"));
130 line = mrb_attr_get(mrb, exc, mrb_intern(mrb, "line"));
131
132 if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
133 str = file;
134 mrb_str_cat2(mrb, str, ":");
135 mrb_str_append(mrb, str, line);
6bdd257 @matz inspect format for exception has changed
matz authored
136 mrb_str_cat2(mrb, str, ": ");
7a7f267 @tsahara-iij check if an Exception instance has a "mesg" attribute
tsahara-iij authored
137 if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
f114916 @matz source position added to exception representation
matz authored
138 mrb_str_append(mrb, str, mesg);
139 mrb_str_cat2(mrb, str, " (");
140 }
141 mrb_str_cat2(mrb, str, mrb_obj_classname(mrb, exc));
7a7f267 @tsahara-iij check if an Exception instance has a "mesg" attribute
tsahara-iij authored
142 if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
f114916 @matz source position added to exception representation
matz authored
143 mrb_str_cat2(mrb, str, ")");
144 }
145 }
146 else {
147 str = mrb_str_new2(mrb, mrb_obj_classname(mrb, exc));
7a7f267 @tsahara-iij check if an Exception instance has a "mesg" attribute
tsahara-iij authored
148 if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
f114916 @matz source position added to exception representation
matz authored
149 mrb_str_cat2(mrb, str, ": ");
150 mrb_str_append(mrb, str, mesg);
7a7f267 @tsahara-iij check if an Exception instance has a "mesg" attribute
tsahara-iij authored
151 } else {
152 mrb_str_cat2(mrb, str, ": ");
153 mrb_str_cat2(mrb, str, mrb_obj_classname(mrb, exc));
f114916 @matz source position added to exception representation
matz authored
154 }
6bdd257 @matz inspect format for exception has changed
matz authored
155 }
e0d6430 @mimaki add mruby sources
mimaki authored
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_sym id_mesg = mrb_intern(mrb, "mesg");
166
167 mrb_get_args(mrb, "o", &obj);
168 if (mrb_obj_equal(mrb, exc, obj)) return mrb_true_value();
169
170 if (mrb_obj_class(mrb, exc) != mrb_obj_class(mrb, obj)) {
d271bf0 @matz make mrb_funcall_argv and mrb_funcall_with_block to take mrb_sym as a…
matz authored
171 if (mrb_respond_to(mrb, obj, mrb_intern(mrb, "message"))) {
e0d6430 @mimaki add mruby sources
mimaki authored
172 mesg = mrb_funcall(mrb, obj, "message", 0);
173 }
174 else
175 return mrb_false_value();
176 }
177 else {
178 mesg = mrb_attr_get(mrb, obj, id_mesg);
179 }
180
181 if (!mrb_equal(mrb, mrb_attr_get(mrb, exc, id_mesg), mesg))
182 return mrb_false_value();
183 return mrb_true_value();
184 }
185
f114916 @matz source position added to exception representation
matz authored
186 static void
187 exc_debug_info(mrb_state *mrb, struct RObject *exc)
188 {
189 mrb_callinfo *ci = mrb->ci;
190 mrb_code *pc = ci->pc;
191
ba0154c @matz should print file:line when exception is raised within mrblib
matz authored
192 ci--;
f114916 @matz source position added to exception representation
matz authored
193 while (ci >= mrb->cibase) {
194 if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
195 mrb_irep *irep = ci->proc->body.irep;
196
4e8317f @matz do no generate lineno info if no filename is specified
matz authored
197 if (irep->filename && irep->lines && irep->iseq <= pc && pc < irep->iseq + irep->ilen) {
f114916 @matz source position added to exception representation
matz authored
198 mrb_obj_iv_set(mrb, exc, mrb_intern(mrb, "file"), mrb_str_new_cstr(mrb, irep->filename));
199 mrb_obj_iv_set(mrb, exc, mrb_intern(mrb, "line"), mrb_fixnum_value(irep->lines[pc - irep->iseq - 1]));
200 return;
201 }
202 }
ba0154c @matz should print file:line when exception is raised within mrblib
matz authored
203 pc = ci->pc;
f114916 @matz source position added to exception representation
matz authored
204 ci--;
205 }
206 }
207
e0d6430 @mimaki add mruby sources
mimaki authored
208 void
209 mrb_exc_raise(mrb_state *mrb, mrb_value exc)
210 {
2830624 @matz fix indent of mrb_exc_raise
matz authored
211 mrb->exc = (struct RObject*)mrb_object(exc);
212 exc_debug_info(mrb, mrb->exc);
213 if (!mrb->jmp) {
214 abort();
215 }
216 longjmp(*(jmp_buf*)mrb->jmp, 1);
e0d6430 @mimaki add mruby sources
mimaki authored
217 }
218
219 void
220 mrb_raise(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
221 {
222 va_list args;
223 char buf[256];
ccec3da @monaka Use return value of vsnprintf() for the string length. It is redundan…
monaka authored
224 int n;
e0d6430 @mimaki add mruby sources
mimaki authored
225
226 va_start(args, fmt);
d534f26 @monaka Use sizeof to get char array sizes.
monaka authored
227 n = vsnprintf(buf, sizeof(buf), fmt, args);
e0d6430 @mimaki add mruby sources
mimaki authored
228 va_end(args);
ccec3da @monaka Use return value of vsnprintf() for the string length. It is redundan…
monaka authored
229 if (n < 0) {
230 n = 0;
231 }
232 mrb_exc_raise(mrb, mrb_exc_new(mrb, c, buf, n));
e0d6430 @mimaki add mruby sources
mimaki authored
233 }
234
235 void
236 mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
237 {
238 mrb_value exc, argv[2];
239 va_list args;
240 char buf[256];
ccec3da @monaka Use return value of vsnprintf() for the string length. It is redundan…
monaka authored
241 int n;
e0d6430 @mimaki add mruby sources
mimaki authored
242
243 va_start(args, fmt);
d534f26 @monaka Use sizeof to get char array sizes.
monaka authored
244 n = vsnprintf(buf, sizeof(buf), fmt, args);
e0d6430 @mimaki add mruby sources
mimaki authored
245 va_end(args);
ccec3da @monaka Use return value of vsnprintf() for the string length. It is redundan…
monaka authored
246 if (n < 0) {
247 n = 0;
248 }
249 argv[0] = mrb_str_new(mrb, buf, n);
742c4fb @matz ignore id to create NameError
matz authored
250 argv[1] = mrb_symbol_value(id); /* ignore now */
251 exc = mrb_class_new_instance(mrb, 1, argv, E_NAME_ERROR);
e0d6430 @mimaki add mruby sources
mimaki authored
252 mrb_exc_raise(mrb, exc);
253 }
df7be84 @matz add newline between functions
matz authored
254
e0d6430 @mimaki add mruby sources
mimaki authored
255 mrb_value
256 mrb_sprintf(mrb_state *mrb, const char *fmt, ...)
257 {
258 va_list args;
259 char buf[256];
ccec3da @monaka Use return value of vsnprintf() for the string length. It is redundan…
monaka authored
260 int n;
e0d6430 @mimaki add mruby sources
mimaki authored
261
262 va_start(args, fmt);
d534f26 @monaka Use sizeof to get char array sizes.
monaka authored
263 n = vsnprintf(buf, sizeof(buf), fmt, args);
e0d6430 @mimaki add mruby sources
mimaki authored
264 va_end(args);
ccec3da @monaka Use return value of vsnprintf() for the string length. It is redundan…
monaka authored
265 if (n < 0) {
266 n = 0;
267 }
268 return mrb_str_new(mrb, buf, n);
e0d6430 @mimaki add mruby sources
mimaki authored
269 }
270
271 void
272 mrb_warn(const char *fmt, ...)
273 {
274 va_list args;
275
276 va_start(args, fmt);
195d1dd @matz do not use fixed sized buffer in mrb_bug/mrb_warn; close #287
matz authored
277 printf("warning: ");
278 vprintf(fmt, args);
e0d6430 @mimaki add mruby sources
mimaki authored
279 va_end(args);
280 }
281
282 void
283 mrb_bug(const char *fmt, ...)
284 {
285 va_list args;
286
287 va_start(args, fmt);
195d1dd @matz do not use fixed sized buffer in mrb_bug/mrb_warn; close #287
matz authored
288 printf("bug: ");
289 vprintf(fmt, args);
e0d6430 @mimaki add mruby sources
mimaki authored
290 va_end(args);
195d1dd @matz do not use fixed sized buffer in mrb_bug/mrb_warn; close #287
matz authored
291 exit(EXIT_FAILURE);
e0d6430 @mimaki add mruby sources
mimaki authored
292 }
293
294 static const char *
295 mrb_strerrno(int err)
296 {
297 #define defined_error(name, num) if (err == num) return name;
298 #define undefined_error(name)
299 //#include "known_errors.inc"
300 #undef defined_error
301 #undef undefined_error
302 return NULL;
303 }
304
305 void
306 mrb_bug_errno(const char *mesg, int errno_arg)
307 {
308 if (errno_arg == 0)
309 mrb_bug("%s: errno == 0 (NOERROR)", mesg);
310 else {
311 const char *errno_str = mrb_strerrno(errno_arg);
312 if (errno_str)
313 mrb_bug("%s: %s (%s)", mesg, strerror(errno_arg), errno_str);
314 else
315 mrb_bug("%s: %s (%d)", mesg, strerror(errno_arg), errno_arg);
316 }
317 }
318
319 int
320 sysexit_status(mrb_state *mrb, mrb_value err)
321 {
322 mrb_value st = mrb_iv_get(mrb, err, mrb_intern(mrb, "status"));
323 return mrb_fixnum(st);
324 }
325
326 static void
327 set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt)
328 {
e5dde46 @matz reduce mrb_funcall invocations
matz authored
329 mrb_funcall(mrb, info, "set_backtrace", 1, bt);
e0d6430 @mimaki add mruby sources
mimaki authored
330 }
331
332 mrb_value
333 make_exception(mrb_state *mrb, int argc, mrb_value *argv, int isstr)
334 {
335 mrb_value mesg;
336 int n;
337
338 mesg = mrb_nil_value();
339 switch (argc) {
340 case 0:
341 break;
342 case 1:
343 if (mrb_nil_p(argv[0]))
344 break;
345 if (isstr) {
346 mesg = mrb_check_string_type(mrb, argv[0]);
347 if (!mrb_nil_p(mesg)) {
ef50e63 @matz remove RuntimeError from mrb_state
matz authored
348 mesg = mrb_exc_new3(mrb, E_RUNTIME_ERROR, mesg);
e0d6430 @mimaki add mruby sources
mimaki authored
349 break;
350 }
351 }
352 n = 0;
353 goto exception_call;
354
355 case 2:
356 case 3:
357 n = 1;
358 exception_call:
d271bf0 @matz make mrb_funcall_argv and mrb_funcall_with_block to take mrb_sym as a…
matz authored
359 {
360 mrb_sym exc = mrb_intern(mrb, "exception");
361 if (mrb_respond_to(mrb, argv[0], exc)) {
362 mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
363 }
364 else {
365 /* undef */
366 mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
367 }
e0d6430 @mimaki add mruby sources
mimaki authored
368 }
369
370 break;
371 default:
372 mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%d for 0..3)", argc);
373 break;
374 }
375 if (argc > 0) {
376 if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
377 mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
378 if (argc > 2)
379 set_backtrace(mrb, mesg, argv[2]);
380 }
381
382 return mesg;
383 }
384
385 mrb_value
386 mrb_make_exception(mrb_state *mrb, int argc, mrb_value *argv)
387 {
388 return make_exception(mrb, argc, argv, TRUE);
389 }
390
391 void
392 mrb_sys_fail(mrb_state *mrb, const char *mesg)
393 {
ef50e63 @matz remove RuntimeError from mrb_state
matz authored
394 mrb_raise(mrb, E_RUNTIME_ERROR, "%s", mesg);
e0d6430 @mimaki add mruby sources
mimaki authored
395 }
396
397 void
398 mrb_init_exception(mrb_state *mrb)
399 {
400 struct RClass *e;
401
402 mrb->eException_class = e = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
403 mrb_define_class_method(mrb, e, "exception", mrb_instance_new, ARGS_ANY());
404 mrb_define_method(mrb, e, "exception", exc_exception, ARGS_ANY());
405 mrb_define_method(mrb, e, "initialize", exc_initialize, ARGS_ANY());
406 mrb_define_method(mrb, e, "==", exc_equal, ARGS_REQ(1));
407 mrb_define_method(mrb, e, "to_s", exc_to_s, ARGS_NONE());
408 mrb_define_method(mrb, e, "message", exc_message, ARGS_NONE());
409 mrb_define_method(mrb, e, "inspect", exc_inspect, ARGS_NONE());
410
ef50e63 @matz remove RuntimeError from mrb_state
matz authored
411 mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
412 mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
9e7ca5d @matz mrb might be intialized incompletely from mrbc; close #457
matz authored
413
414 mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */
415 e = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */
416 mrb_define_class(mrb, "SyntaxError", e); /* 15.2.38 */
e0d6430 @mimaki add mruby sources
mimaki authored
417 }
Something went wrong with that request. Please try again.