static void exc_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func func, void *stream) { mrb_value lastpc; mrb_code *code; lastpc = mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "lastpc")); if (mrb_nil_p(lastpc)) { code = NULL; } else { code = (mrb_code*)mrb_cptr(lastpc); } output_backtrace(mrb, mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "ciidx"))), code, func, stream); }
mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c) { mrb_value path; const char *name; size_t len; mrb_sym classpath = mrb_intern2(mrb, "__classpath__", 13); path = mrb_obj_iv_get(mrb, (struct RObject*)c, classpath); if (mrb_nil_p(path)) { struct RClass *outer = mrb_class_outer_module(mrb, c); mrb_sym sym = mrb_class_sym(mrb, c, outer); if (sym == 0) { return mrb_nil_value(); } else if (outer && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); path = mrb_str_plus(mrb, base, mrb_str_new(mrb, "::", 2)); name = mrb_sym2name_len(mrb, sym, &len); mrb_str_concat(mrb, path, mrb_str_new(mrb, name, len)); } else { name = mrb_sym2name_len(mrb, sym, &len); path = mrb_str_new(mrb, name, len); } mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path); } return path; }
mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) { if (obj_iv_p(obj)) { return mrb_obj_iv_get(mrb, mrb_obj_ptr(obj), sym); } return mrb_nil_value(); }
struct RClass* mrb_class_outer_module(mrb_state *mrb, struct RClass *c) { mrb_value outer; outer = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__outer__")); if (mrb_nil_p(outer)) return 0; return mrb_class_ptr(outer); }
struct mrb_ffi_type* rclass_to_mrb_ffi_type(mrb_state *mrb, struct RClass *cls) { struct RClass *cls_ = cls; while(cls) { mrb_value ffi_type = mrb_obj_iv_get(mrb, (struct RObject*)cls, mrb_intern_cstr(mrb, "@ffi_type")); if(mrb_test(ffi_type)) { return (struct mrb_ffi_type*)DATA_PTR(ffi_type); } cls = cls->super; } mrb_raisef(mrb, E_TYPE_ERROR, "%s cannot convert to C value", mrb_class_name(mrb, cls_)); return NULL; }
static struct RClass* outer_class(mrb_state *mrb, struct RClass *c) { mrb_value ov; ov = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__")); if (mrb_nil_p(ov)) return NULL; switch (mrb_type(ov)) { case MRB_TT_CLASS: case MRB_TT_MODULE: return mrb_class_ptr(ov); default: break; } return NULL; }
mrb_sym mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer) { mrb_value name; name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classid__")); if (mrb_nil_p(name)) { struct csym_arg arg; arg.c = c; arg.sym = 0; iv_foreach(mrb, outer->iv, csym_i, &arg); return arg.sym; } return SYM2ID(name); }
static void showcallinfo(mrb_state *mrb) { mrb_callinfo *ci; mrb_int ciidx; const char *filename, *method, *sep; int i, line; printf("trace:\n"); ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern(mrb, "ciidx"))); if (ciidx >= mrb->ciend - mrb->cibase) ciidx = 10; /* ciidx is broken... */ for (i = ciidx; i >= 0; i--) { ci = &mrb->cibase[i]; filename = "(unknown)"; line = -1; if (MRB_PROC_CFUNC_P(ci->proc)) { continue; } else { mrb_irep *irep = ci->proc->body.irep; if (irep->filename != NULL) filename = irep->filename; if (irep->lines != NULL && i+1 <= ciidx) { mrb_code *pc = mrb->cibase[i+1].pc; if (irep->iseq <= pc && pc < irep->iseq + irep->ilen) { line = irep->lines[pc - irep->iseq - 1]; } } } if (ci->target_class == ci->proc->target_class) sep = "."; else sep = "#"; method = mrb_sym2name(mrb, ci->mid); printf("\t[%d] %s:%d%s%s%s%s\n", i, filename, line, method ? ":in " : "", method ? mrb_class_name(mrb, ci->proc->target_class) : "", method ? sep : "", method ? method : ""); } }
MRB_API void mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) { struct RClass * cls = c; while (c) { if (c->iv) { iv_tbl *t = c->iv; if (iv_get(mrb, t, sym, NULL)) { mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, t, sym, v); return; } } c = c->super; } if (cls && cls->tt == MRB_TT_SCLASS) { mrb_value klass; klass = mrb_obj_iv_get(mrb, (struct RObject*)cls, mrb_intern_lit(mrb, "__attached__")); switch (mrb_type(klass)) { case MRB_TT_CLASS: case MRB_TT_MODULE: case MRB_TT_SCLASS: c = mrb_class_ptr(klass); break; default: c = cls; break; } } else{ c = cls; } if (!c->iv) { c->iv = iv_new(mrb); } mrb_write_barrier(mrb, (struct RBasic*)c); iv_put(mrb, c->iv, sym, v); }
static mrb_sym class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer) { mrb_value name; name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classid__")); if (mrb_nil_p(name)) { khash_t(iv)* h; khiter_t k; mrb_value v; if (!outer) outer = mrb->object_class; h = outer->iv; for (k = kh_begin(h); k != kh_end(h); k++) { if (!kh_exist(h,k)) continue; v = kh_value(h,k); if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) { return kh_key(h,k); } } } return SYM2ID(name); }
MRB_API void mrb_print_backtrace(mrb_state *mrb) { mrb_value backtrace; if (!mrb->exc) { return; } backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace")); if (!mrb_nil_p(backtrace)) { print_backtrace(mrb, backtrace); } else if (mrb->backtrace.n > 0) { print_backtrace_saved(mrb); } else { struct print_backtrace_args args; args.stream = stderr; args.tracehead = TRUE; exc_output_backtrace(mrb, mrb->exc, print_backtrace_i, (void*)&args); } }
mrb_value mrb_class_path(mrb_state *mrb, struct RClass *c) { mrb_value path; path = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__")); if (mrb_nil_p(path)) { struct RClass *outer = mrb_class_outer_module(mrb, c); mrb_sym sym = class_sym(mrb, c, outer); if (outer && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); path = mrb_str_plus(mrb, base, mrb_str_new_cstr(mrb, "::")); mrb_str_concat(mrb, path, mrb_str_new_cstr(mrb, mrb_sym2name(mrb, sym))); } else if (sym == 0) { return mrb_nil_value(); } else { path = mrb_str_new_cstr(mrb, mrb_sym2name(mrb, sym)); } mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern(mrb, "__classpath__"), path); } return path; }
MRB_API mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) { struct RClass * cls = c; mrb_value v; int given = FALSE; while (c) { if (c->iv && iv_get(mrb, c->iv, sym, &v)) { given = TRUE; } c = c->super; } if (given) return v; if (cls && cls->tt == MRB_TT_SCLASS) { mrb_value klass; klass = mrb_obj_iv_get(mrb, (struct RObject *)cls, mrb_intern_lit(mrb, "__attached__")); c = mrb_class_ptr(klass); if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) { given = FALSE; while (c) { if (c->iv && iv_get(mrb, c->iv, sym, &v)) { given = TRUE; } c = c->super; } if (given) return v; } } mrb_name_error(mrb, sym, "uninitialized class variable %S in %S", mrb_sym2str(mrb, sym), mrb_obj_value(cls)); /* not reached */ return mrb_nil_value(); }
void mrb_print_backtrace(mrb_state *mrb) { #ifdef ENABLE_STDIO mrb_callinfo *ci; mrb_int ciidx; const char *filename, *method, *sep; int i, line; printf("trace:\n"); ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern(mrb, "ciidx"))); if (ciidx >= mrb->ciend - mrb->cibase) ciidx = 10; /* ciidx is broken... */ for (i = ciidx; i >= 0; i--) { ci = &mrb->cibase[i]; filename = "(unknown)"; line = -1; if (MRB_PROC_CFUNC_P(ci->proc)) { continue; } else { mrb_irep *irep = ci->proc->body.irep; if (irep->filename != NULL) filename = irep->filename; if (irep->lines != NULL) { mrb_code *pc; if (i+1 <= ciidx) { pc = mrb->cibase[i+1].pc; } else { pc = (mrb_code*)mrb_voidp(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern(mrb, "lastpc"))); } if (irep->iseq <= pc && pc < irep->iseq + irep->ilen) { line = irep->lines[pc - irep->iseq - 1]; } } } if (line == -1) continue; if (ci->target_class == ci->proc->target_class) sep = "."; else sep = "#"; method = mrb_sym2name(mrb, ci->mid); if (method) { const char *cn = mrb_class_name(mrb, ci->proc->target_class); if (cn) { printf("\t[%d] %s:%d:in %s%s%s\n", i, filename, line, cn, sep, method); } else { printf("\t[%d] %s:%d:in %s\n", i, filename, line, method); } } else { printf("\t[%d] %s:%d\n", i, filename, line); } } #endif }
static mrb_bool have_backtrace(mrb_state *mrb, struct RObject *exc) { return !mrb_nil_p(mrb_obj_iv_get(mrb, exc, mrb_intern_lit(mrb, "backtrace"))); }