Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mruby_mbed_web mirb_mbed
error.c
00001 /* 00002 ** error.c - Exception class 00003 ** 00004 ** See Copyright Notice in mruby.h 00005 */ 00006 00007 #include <errno.h> 00008 #include <stdarg.h> 00009 #include <stdlib.h> 00010 #include "mruby.h" 00011 #include "mruby/array.h" 00012 #include "mruby/irep.h" 00013 #include "mruby/proc.h" 00014 #include "mruby/string.h" 00015 #include "mruby/variable.h" 00016 #include "mruby/debug.h" 00017 #include "mruby/error.h" 00018 #include "mruby/class.h" 00019 #include "mrb_throw.h" 00020 00021 MRB_API mrb_value 00022 mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len) 00023 { 00024 mrb_value arg = mrb_str_new(mrb, ptr, len); 00025 return mrb_obj_new(mrb, c, 1, &arg); 00026 } 00027 00028 MRB_API mrb_value 00029 mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str) 00030 { 00031 str = mrb_str_to_str(mrb, str); 00032 return mrb_obj_new(mrb, c, 1, &str); 00033 } 00034 00035 /* 00036 * call-seq: 00037 * Exception.new(msg = nil) -> exception 00038 * 00039 * Construct a new Exception object, optionally passing in 00040 * a message. 00041 */ 00042 00043 static mrb_value 00044 exc_initialize(mrb_state *mrb, mrb_value exc) 00045 { 00046 mrb_value mesg; 00047 00048 if (mrb_get_args(mrb, "|o", &mesg) == 1) { 00049 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg); 00050 } 00051 return exc; 00052 } 00053 00054 /* 00055 * Document-method: exception 00056 * 00057 * call-seq: 00058 * exc.exception(string) -> an_exception or exc 00059 * 00060 * With no argument, or if the argument is the same as the receiver, 00061 * return the receiver. Otherwise, create a new 00062 * exception object of the same class as the receiver, but with a 00063 * message equal to <code>string.to_str</code>. 00064 * 00065 */ 00066 00067 static mrb_value 00068 exc_exception(mrb_state *mrb, mrb_value self) 00069 { 00070 mrb_value exc; 00071 mrb_value a; 00072 int argc; 00073 00074 argc = mrb_get_args(mrb, "|o", &a); 00075 if (argc == 0) return self; 00076 if (mrb_obj_equal(mrb, self, a)) return self; 00077 exc = mrb_obj_clone(mrb, self); 00078 mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a); 00079 00080 return exc; 00081 } 00082 00083 /* 00084 * call-seq: 00085 * exception.to_s -> string 00086 * 00087 * Returns exception's message (or the name of the exception if 00088 * no message is set). 00089 */ 00090 00091 static mrb_value 00092 exc_to_s(mrb_state *mrb, mrb_value exc) 00093 { 00094 mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg")); 00095 struct RObject *p; 00096 00097 if (!mrb_string_p(mesg)) { 00098 return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc)); 00099 } 00100 p = mrb_obj_ptr(mesg); 00101 if (!p->c) { 00102 p->c = mrb->string_class; 00103 } 00104 return mesg; 00105 } 00106 00107 /* 00108 * call-seq: 00109 * exception.message -> string 00110 * 00111 * Returns the result of invoking <code>exception.to_s</code>. 00112 * Normally this returns the exception's message or name. By 00113 * supplying a to_str method, exceptions are agreeing to 00114 * be used where Strings are expected. 00115 */ 00116 00117 static mrb_value 00118 exc_message(mrb_state *mrb, mrb_value exc) 00119 { 00120 return mrb_funcall(mrb, exc, "to_s", 0); 00121 } 00122 00123 /* 00124 * call-seq: 00125 * exception.inspect -> string 00126 * 00127 * Returns this exception's file name, line number, 00128 * message and class name. 00129 * If file name or line number is not set, 00130 * returns message and class name. 00131 */ 00132 00133 static mrb_value 00134 exc_inspect(mrb_state *mrb, mrb_value exc) 00135 { 00136 mrb_value str, mesg, file, line; 00137 mrb_bool append_mesg; 00138 00139 mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg")); 00140 file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file")); 00141 line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line")); 00142 00143 append_mesg = !mrb_nil_p(mesg); 00144 if (append_mesg) { 00145 mesg = mrb_obj_as_string(mrb, mesg); 00146 append_mesg = RSTRING_LEN(mesg) > 0; 00147 } 00148 00149 if (!mrb_nil_p(file) && !mrb_nil_p(line)) { 00150 str = mrb_str_dup(mrb, file); 00151 mrb_str_cat_lit(mrb, str, ":"); 00152 mrb_str_append(mrb, str, line); 00153 mrb_str_cat_lit(mrb, str, ": "); 00154 if (append_mesg) { 00155 mrb_str_append(mrb, str, mesg); 00156 mrb_str_cat_lit(mrb, str, " ("); 00157 } 00158 mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc)); 00159 if (append_mesg) { 00160 mrb_str_cat_lit(mrb, str, ")"); 00161 } 00162 } 00163 else { 00164 const char *cname = mrb_obj_classname(mrb, exc); 00165 str = mrb_str_new_cstr(mrb, cname); 00166 mrb_str_cat_lit(mrb, str, ": "); 00167 if (append_mesg) { 00168 mrb_str_append(mrb, str, mesg); 00169 } 00170 else { 00171 mrb_str_cat_cstr(mrb, str, cname); 00172 } 00173 } 00174 return str; 00175 } 00176 00177 00178 static void 00179 exc_debug_info(mrb_state *mrb, struct RObject *exc) 00180 { 00181 mrb_callinfo *ci = mrb->c->ci; 00182 mrb_code *pc = ci->pc; 00183 00184 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value((mrb_int)(ci - mrb->c->cibase))); 00185 while (ci >= mrb->c->cibase) { 00186 mrb_code *err = ci->err; 00187 00188 if (!err && pc) err = pc - 1; 00189 if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) { 00190 mrb_irep *irep = ci->proc->body.irep; 00191 00192 int32_t const line = mrb_debug_get_line(irep, (uint32_t)(err - irep->iseq)); 00193 char const* file = mrb_debug_get_filename(irep, (uint32_t)(err - irep->iseq)); 00194 if (line != -1 && file) { 00195 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file)); 00196 mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line)); 00197 return; 00198 } 00199 } 00200 pc = ci->pc; 00201 ci--; 00202 } 00203 } 00204 00205 MRB_API mrb_noreturn void 00206 mrb_exc_raise(mrb_state *mrb, mrb_value exc) 00207 { 00208 mrb->exc = mrb_obj_ptr(exc); 00209 if (!mrb->out_of_memory) { 00210 exc_debug_info(mrb, mrb->exc); 00211 } 00212 if (!mrb->jmp) { 00213 mrb_p(mrb, exc); 00214 abort(); 00215 } 00216 MRB_THROW(mrb->jmp); 00217 } 00218 00219 MRB_API mrb_noreturn void 00220 mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg) 00221 { 00222 mrb_value mesg; 00223 mesg = mrb_str_new_cstr(mrb, msg); 00224 mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg)); 00225 } 00226 00227 MRB_API mrb_value 00228 mrb_vformat(mrb_state *mrb, const char *format, va_list ap) 00229 { 00230 const char *p = format; 00231 const char *b = p; 00232 ptrdiff_t size; 00233 mrb_value ary = mrb_ary_new_capa(mrb, 4); 00234 00235 while (*p) { 00236 const char c = *p++; 00237 00238 if (c == '%') { 00239 if (*p == 'S') { 00240 size = p - b - 1; 00241 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); 00242 mrb_ary_push(mrb, ary, va_arg(ap, mrb_value)); 00243 b = p + 1; 00244 } 00245 } 00246 else if (c == '\\') { 00247 if (*p) { 00248 size = p - b - 1; 00249 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); 00250 mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1)); 00251 b = ++p; 00252 } 00253 else { 00254 break; 00255 } 00256 } 00257 } 00258 if (b == format) { 00259 return mrb_str_new_cstr(mrb, format); 00260 } 00261 else { 00262 size = p - b; 00263 mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size)); 00264 return mrb_ary_join(mrb, ary, mrb_str_new(mrb, NULL, 0)); 00265 } 00266 } 00267 00268 MRB_API mrb_value 00269 mrb_format(mrb_state *mrb, const char *format, ...) 00270 { 00271 va_list ap; 00272 mrb_value str; 00273 00274 va_start(ap, format); 00275 str = mrb_vformat(mrb, format, ap); 00276 va_end(ap); 00277 00278 return str; 00279 } 00280 00281 MRB_API mrb_noreturn void 00282 mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...) 00283 { 00284 va_list args; 00285 mrb_value mesg; 00286 00287 va_start(args, fmt); 00288 mesg = mrb_vformat(mrb, fmt, args); 00289 va_end(args); 00290 mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mesg)); 00291 } 00292 00293 MRB_API mrb_noreturn void 00294 mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...) 00295 { 00296 mrb_value exc; 00297 mrb_value argv[2]; 00298 va_list args; 00299 00300 va_start(args, fmt); 00301 argv[0] = mrb_vformat(mrb, fmt, args); 00302 va_end(args); 00303 00304 argv[1] = mrb_symbol_value(id); 00305 exc = mrb_obj_new(mrb, E_NAME_ERROR, 2, argv); 00306 mrb_exc_raise(mrb, exc); 00307 } 00308 00309 MRB_API void 00310 mrb_warn(mrb_state *mrb, const char *fmt, ...) 00311 { 00312 #ifdef ENABLE_STDIO 00313 va_list ap; 00314 mrb_value str; 00315 00316 va_start(ap, fmt); 00317 str = mrb_vformat(mrb, fmt, ap); 00318 fputs("warning: ", stderr); 00319 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); 00320 va_end(ap); 00321 #endif 00322 } 00323 00324 MRB_API mrb_noreturn void 00325 mrb_bug(mrb_state *mrb, const char *fmt, ...) 00326 { 00327 #ifdef ENABLE_STDIO 00328 va_list ap; 00329 mrb_value str; 00330 00331 va_start(ap, fmt); 00332 str = mrb_vformat(mrb, fmt, ap); 00333 fputs("bug: ", stderr); 00334 fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr); 00335 va_end(ap); 00336 #endif 00337 exit(EXIT_FAILURE); 00338 } 00339 00340 static void 00341 set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt) 00342 { 00343 mrb_funcall(mrb, info, "set_backtrace", 1, bt); 00344 } 00345 00346 static mrb_value 00347 make_exception(mrb_state *mrb, int argc, const mrb_value *argv, mrb_bool isstr) 00348 { 00349 mrb_value mesg; 00350 int n; 00351 00352 mesg = mrb_nil_value(); 00353 switch (argc) { 00354 case 0: 00355 break; 00356 case 1: 00357 if (mrb_nil_p(argv[0])) 00358 break; 00359 if (isstr) { 00360 mesg = mrb_check_string_type(mrb, argv[0]); 00361 if (!mrb_nil_p(mesg)) { 00362 mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, mesg); 00363 break; 00364 } 00365 } 00366 n = 0; 00367 goto exception_call; 00368 00369 case 2: 00370 case 3: 00371 n = 1; 00372 exception_call: 00373 { 00374 mrb_sym exc = mrb_intern_lit(mrb, "exception"); 00375 if (mrb_respond_to(mrb, argv[0], exc)) { 00376 mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1); 00377 } 00378 else { 00379 /* undef */ 00380 mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected"); 00381 } 00382 } 00383 00384 break; 00385 default: 00386 mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc)); 00387 break; 00388 } 00389 if (argc > 0) { 00390 if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class)) 00391 mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); 00392 if (argc > 2) 00393 set_backtrace(mrb, mesg, argv[2]); 00394 } 00395 00396 return mesg; 00397 } 00398 00399 MRB_API mrb_value 00400 mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv) 00401 { 00402 return make_exception(mrb, argc, argv, TRUE); 00403 } 00404 00405 MRB_API void 00406 mrb_sys_fail(mrb_state *mrb, const char *mesg) 00407 { 00408 struct RClass *sce; 00409 mrb_int no; 00410 00411 no = (mrb_int)errno; 00412 if (mrb_class_defined(mrb, "SystemCallError")) { 00413 sce = mrb_class_get(mrb, "SystemCallError"); 00414 if (mesg != NULL) { 00415 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg)); 00416 } 00417 else { 00418 mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no)); 00419 } 00420 } 00421 else { 00422 mrb_raise(mrb, E_RUNTIME_ERROR, mesg); 00423 } 00424 } 00425 00426 MRB_API mrb_noreturn void 00427 mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, char const* fmt, ...) 00428 { 00429 mrb_value exc; 00430 va_list ap; 00431 00432 va_start(ap, fmt); 00433 exc = mrb_funcall(mrb, mrb_obj_value(E_NOMETHOD_ERROR), "new", 3, 00434 mrb_vformat(mrb, fmt, ap), mrb_symbol_value(id), 00435 mrb_ary_new_from_values(mrb, argc, argv)); 00436 va_end(ap); 00437 mrb_exc_raise(mrb, exc); 00438 } 00439 00440 void 00441 mrb_init_exception(mrb_state *mrb) 00442 { 00443 struct RClass *exception, *runtime_error, *script_error; 00444 00445 mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */ 00446 MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION); 00447 mrb_define_class_method(mrb, exception, "exception", mrb_instance_new, MRB_ARGS_ANY()); 00448 mrb_define_method(mrb, exception, "exception", exc_exception, MRB_ARGS_ANY()); 00449 mrb_define_method(mrb, exception, "initialize", exc_initialize, MRB_ARGS_ANY()); 00450 mrb_define_method(mrb, exception, "to_s", exc_to_s, MRB_ARGS_NONE()); 00451 mrb_define_method(mrb, exception, "message", exc_message, MRB_ARGS_NONE()); 00452 mrb_define_method(mrb, exception, "inspect", exc_inspect, MRB_ARGS_NONE()); 00453 mrb_define_method(mrb, exception, "backtrace", mrb_exc_backtrace, MRB_ARGS_NONE()); 00454 00455 mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ 00456 runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ 00457 mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str(mrb, runtime_error, mrb_str_new_lit(mrb, "Out of memory"))); 00458 script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ 00459 mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */ 00460 mrb_define_class(mrb, "SystemStackError", exception); 00461 } 00462
Generated on Tue Jul 12 2022 18:00:34 by
1.7.2