#include #include #include #include #include #include #include #include #include #include /* * call-seq: * caller(start = 1) -> array or nil * caller(range) -> array or nil * caller(start, length) -> array or nil * * Returns the current execution stack as an array of strings in the form * "file:line" or "file:line:in `method'". The optional start parameter * determines the number of initial stack entries to omit from the top of the stack. * * def a(skip) * caller(skip) * end * def b * a(0) * end * def c * b * end * c #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10:in `
'"] */ static mrb_value mrb_f_caller(mrb_state *mrb, mrb_value self) { mrb_value bt, v; mrb_int bt_len, argc, lev, n; argc = mrb_get_args(mrb, "|oi", &v, &n); bt = mrb_get_backtrace(mrb); bt_len = RARRAY_LEN(bt); switch (argc) { case 0: lev = 1; n = bt_len - 1; break; case 1: if (mrb_range_p(v)) { mrb_int beg, len; if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == MRB_RANGE_OK) { lev = beg; n = len; } else { return mrb_nil_value(); } } else { lev = mrb_as_int(mrb, v); if (lev < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%v)", v); } n = bt_len - lev; } break; case 2: lev = mrb_as_int(mrb, v); break; default: /* not reached */ lev = n = 0; break; } if (lev >= bt_len) return mrb_nil_value(); if (lev < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative level (%v)", v); } if (n < 0) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%d)", n); } if (n == 0) { return mrb_ary_new(mrb); } if (bt_len <= n + lev) n = bt_len - lev - 1; return mrb_ary_new_from_values(mrb, n, RARRAY_PTR(bt)+lev+1); } /* * call-seq: * __method__ -> symbol * * Returns the called name of the current method as a Symbol. * If called outside of a method, it returns `nil`. * */ static mrb_value mrb_f_method(mrb_state *mrb, mrb_value self) { mrb_callinfo *ci = mrb->c->ci; ci--; if (ci->proc && ci->proc->e.env && ci->proc->e.env->tt == MRB_TT_ENV && ci->proc->e.env->mid) return mrb_symbol_value(ci->proc->e.env->mid); else if (ci->mid) return mrb_symbol_value(ci->mid); else return mrb_nil_value(); } /* * call-seq: * __callee__ -> symbol * * Returns the called name of the current method as a Symbol. * If called outside of a method, it returns `nil`. * */ static mrb_value mrb_f_callee(mrb_state *mrb, mrb_value self) { mrb_callinfo *ci = mrb->c->ci; ci--; if (ci->mid) return mrb_symbol_value(ci->mid); else return mrb_nil_value(); } /* * call-seq: * Integer(arg,base=0) -> integer * * Converts *arg* to a `Integer`. * Numeric types are converted directly (with floating-point numbers * being truncated). *base* (0, or between 2 and 36) is a base for * integer string representation. If *arg* is a `String`, * when *base* is omitted or equals to zero, radix indicators * (`0`, `0b`, and `0x`) are honored. * In any case, strings should be strictly conformed to numeric * representation. This behavior is different from that of * `String#to_i`. Non string values will be treated as integers. * Passing `nil` raises a TypeError. * * Integer(123.999) #=> 123 * Integer("0x1a") #=> 26 * Integer(Time.new) #=> 1204973019 * Integer("0930", 10) #=> 930 * Integer("111", 2) #=> 7 * Integer(nil) #=> TypeError */ static mrb_noreturn void arg_error(mrb_state *mrb) { mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); } static mrb_value mrb_f_integer(mrb_state *mrb, mrb_value self) { mrb_value val, tmp; mrb_int base = 0; mrb_get_args(mrb, "o|i", &val, &base); if (mrb_nil_p(val)) { if (base != 0) arg_error(mrb); mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); } switch (mrb_type(val)) { #ifndef MRB_NO_FLOAT case MRB_TT_FLOAT: if (base != 0) arg_error(mrb); return mrb_float_to_integer(mrb, val); #endif case MRB_TT_INTEGER: if (base != 0) arg_error(mrb); return val; case MRB_TT_STRING: string_conv: return mrb_str_to_integer(mrb, val, base, TRUE); default: break; } if (base != 0) { tmp = mrb_obj_as_string(mrb, val); if (mrb_string_p(tmp)) { val = tmp; goto string_conv; } arg_error(mrb); } /* to raise TypeError */ return mrb_ensure_integer_type(mrb, val); } #ifndef MRB_NO_FLOAT /* * call-seq: * Float(arg) -> float * * Returns *arg* converted to a float. Numeric types are converted * directly, the rest are converted using *arg*.to_f. * * Float(1) #=> 1.0 * Float(123.456) #=> 123.456 * Float("123.456") #=> 123.456 * Float(nil) #=> TypeError */ static mrb_value mrb_f_float(mrb_state *mrb, mrb_value self) { mrb_value arg = mrb_get_arg1(mrb); if (mrb_string_p(arg)) { return mrb_float_value(mrb, mrb_str_to_dbl(mrb, arg, TRUE)); } return mrb_ensure_float_type(mrb, arg); } #endif /* * call-seq: * String(arg) -> string * * Returns *arg* as an `String`. * converted using `to_s` method. * * String(self) #=> "main" * String(self.class) #=> "Object" * String(123456) #=> "123456" */ static mrb_value mrb_f_string(mrb_state *mrb, mrb_value self) { mrb_value arg = mrb_get_arg1(mrb); mrb_value tmp = mrb_type_convert(mrb, arg, MRB_TT_STRING, MRB_SYM(to_s)); return tmp; } /* * call-seq: * Array(arg) -> array * * Returns `arg` as an Array using to_a method. * * Array(1..5) #=> [1, 2, 3, 4, 5] * */ static mrb_value mrb_f_array(mrb_state *mrb, mrb_value self) { mrb_value arg = mrb_get_arg1(mrb); mrb_value tmp = mrb_type_convert_check(mrb, arg, MRB_TT_ARRAY, MRB_SYM(to_a)); if (mrb_nil_p(tmp)) { return mrb_ary_new_from_values(mrb, 1, &arg); } return tmp; } /* * call-seq: * Hash(arg) -> hash * * Returns a `Hash` if *arg* is a `Hash`. * Returns an empty `Hash` when *arg* is `nil` * or `[]`. * * Hash([]) #=> {} * Hash(nil) #=> {} * Hash(key: :value) #=> {:key => :value} * Hash([1, 2, 3]) #=> TypeError * */ static mrb_value mrb_f_hash(mrb_state *mrb, mrb_value self) { mrb_value arg = mrb_get_arg1(mrb); if (mrb_nil_p(arg) || (mrb_array_p(arg) && RARRAY_LEN(arg) == 0)) { return mrb_hash_new(mrb); } mrb_ensure_hash_type(mrb, arg); return arg; } static const mrb_mt_entry kernel_ext_rom_entries[] = { MRB_MT_ENTRY(mrb_f_raise, MRB_SYM(fail), MRB_ARGS_OPT(2) | MRB_MT_PRIVATE), MRB_MT_ENTRY(mrb_f_caller, MRB_SYM(caller), MRB_ARGS_OPT(2) | MRB_MT_PRIVATE), MRB_MT_ENTRY(mrb_f_method, MRB_SYM(__method__), MRB_ARGS_NONE() | MRB_MT_PRIVATE), MRB_MT_ENTRY(mrb_f_callee, MRB_SYM(__callee__), MRB_ARGS_NONE() | MRB_MT_PRIVATE), MRB_MT_ENTRY(mrb_f_integer, MRB_SYM(Integer), MRB_ARGS_ARG(1,1) | MRB_MT_PRIVATE), MRB_MT_ENTRY(mrb_f_string, MRB_SYM(String), MRB_ARGS_REQ(1) | MRB_MT_PRIVATE), MRB_MT_ENTRY(mrb_f_array, MRB_SYM(Array), MRB_ARGS_REQ(1) | MRB_MT_PRIVATE), #ifndef MRB_NO_FLOAT MRB_MT_ENTRY(mrb_f_float, MRB_SYM(Float), MRB_ARGS_REQ(1) | MRB_MT_PRIVATE), #endif MRB_MT_ENTRY(mrb_f_hash, MRB_SYM(Hash), MRB_ARGS_REQ(1) | MRB_MT_PRIVATE), }; void mrb_mruby_kernel_ext_gem_init(mrb_state *mrb) { struct RClass *krn = mrb->kernel_module; MRB_MT_INIT_ROM(mrb, krn, kernel_ext_rom_entries); } void mrb_mruby_kernel_ext_gem_final(mrb_state *mrb) { }