#include "mruby.h" #include "mruby/proc.h" #include "mruby/opcode.h" #include "mruby/array.h" #include "mruby/string.h" #include "mruby/debug.h" static mrb_value mrb_proc_lambda(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); return mrb_bool_value(MRB_PROC_STRICT_P(p)); } static mrb_value mrb_proc_source_location(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); if (MRB_PROC_CFUNC_P(p)) { return mrb_nil_value(); } else { mrb_irep *irep = p->body.irep; int32_t line; const char *filename; filename = mrb_debug_get_filename(irep, 0); line = mrb_debug_get_line(irep, 0); return (!filename && line == -1)? mrb_nil_value() : mrb_assoc_new(mrb, mrb_str_new_cstr(mrb, filename), mrb_fixnum_value(line)); } } static mrb_value mrb_proc_inspect(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); mrb_value str = mrb_str_new_lit(mrb, "#body.irep; const char *filename; int32_t line; mrb_str_cat_lit(mrb, str, "@"); filename = mrb_debug_get_filename(irep, 0); mrb_str_cat_cstr(mrb, str, filename ? filename : "-"); mrb_str_cat_lit(mrb, str, ":"); line = mrb_debug_get_line(irep, 0); if (line != -1) { mrb_str_append(mrb, str, mrb_fixnum_value(line)); } else { mrb_str_cat_lit(mrb, str, "-"); } } if (MRB_PROC_STRICT_P(p)) { mrb_str_cat_lit(mrb, str, " (lambda)"); } mrb_str_cat_lit(mrb, str, ">"); return str; } static mrb_value mrb_kernel_proc(mrb_state *mrb, mrb_value self) { mrb_value blk; mrb_get_args(mrb, "&", &blk); if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); } return blk; } /* * call-seq: * prc.parameters -> array * * Returns the parameter information of this proc. * * prc = lambda{|x, y=42, *other|} * prc.parameters #=> [[:req, :x], [:opt, :y], [:rest, :other]] */ static mrb_value mrb_proc_parameters(mrb_state *mrb, mrb_value self) { struct parameters_type { int size; const char *name; } *p, parameters_list [] = { {0, "req"}, {0, "opt"}, {0, "rest"}, {0, "req"}, {0, "block"}, {0, NULL} }; const struct RProc *proc = mrb_proc_ptr(self); const struct mrb_irep *irep = proc->body.irep; mrb_aspec aspec; mrb_value parameters; int i, j; if (MRB_PROC_CFUNC_P(proc)) { // TODO cfunc aspec is not implemented yet return mrb_ary_new(mrb); } if (!irep->lv) { return mrb_ary_new(mrb); } if (GET_OPCODE(*irep->iseq) != OP_ENTER) { return mrb_ary_new(mrb); } if (!MRB_PROC_STRICT_P(proc)) { parameters_list[0].name = "opt"; parameters_list[3].name = "opt"; } aspec = GETARG_Ax(*irep->iseq); parameters_list[0].size = MRB_ASPEC_REQ(aspec); parameters_list[1].size = MRB_ASPEC_OPT(aspec); parameters_list[2].size = MRB_ASPEC_REST(aspec); parameters_list[3].size = MRB_ASPEC_POST(aspec); parameters_list[4].size = MRB_ASPEC_BLOCK(aspec); parameters = mrb_ary_new_capa(mrb, irep->nlocals-1); for (i = 0, p = parameters_list; p->name; p++) { mrb_value sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name)); for (j = 0; j < p->size; i++, j++) { mrb_assert(i < (irep->nlocals-1)); mrb_ary_push(mrb, parameters, mrb_assoc_new(mrb, sname, mrb_symbol_value(irep->lv[i].name) )); } } return parameters; } void mrb_mruby_proc_ext_gem_init(mrb_state* mrb) { struct RClass *p = mrb->proc_class; mrb_define_method(mrb, p, "lambda?", mrb_proc_lambda, MRB_ARGS_NONE()); mrb_define_method(mrb, p, "source_location", mrb_proc_source_location, MRB_ARGS_NONE()); mrb_define_method(mrb, p, "to_s", mrb_proc_inspect, MRB_ARGS_NONE()); mrb_define_method(mrb, p, "inspect", mrb_proc_inspect, MRB_ARGS_NONE()); mrb_define_method(mrb, p, "parameters", mrb_proc_parameters, MRB_ARGS_NONE()); mrb_define_class_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); mrb_define_method(mrb, mrb->kernel_module, "proc", mrb_kernel_proc, MRB_ARGS_NONE()); } void mrb_mruby_proc_ext_gem_final(mrb_state* mrb) { }