diff options
| author | ksss <[email protected]> | 2014-06-25 15:55:59 +0900 |
|---|---|---|
| committer | ksss <[email protected]> | 2014-06-25 16:05:33 +0900 |
| commit | 9cafc5e1051765d67d451f4b456996300ddf355c (patch) | |
| tree | a641137ba26861a6be1d3ad43ebb2ab405228de4 /mrbgems/mruby-proc-ext | |
| parent | d4e49c9f8fe752e8f7d3d6b9dc10a55307654dfd (diff) | |
| download | mruby-9cafc5e1051765d67d451f4b456996300ddf355c.tar.gz mruby-9cafc5e1051765d67d451f4b456996300ddf355c.zip | |
Implement Proc#parameters
Diffstat (limited to 'mrbgems/mruby-proc-ext')
| -rw-r--r-- | mrbgems/mruby-proc-ext/src/proc.c | 69 | ||||
| -rw-r--r-- | mrbgems/mruby-proc-ext/test/proc.rb | 12 |
2 files changed, 81 insertions, 0 deletions
diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index b105c95d7..f4a238803 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -1,5 +1,6 @@ #include "mruby.h" #include "mruby/proc.h" +#include "mruby/opcode.h" #include "mruby/array.h" #include "mruby/string.h" #include "mruby/debug.h" @@ -122,6 +123,73 @@ mrb_kernel_proc(mrb_state *mrb, mrb_value self) 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) { @@ -130,6 +198,7 @@ mrb_mruby_proc_ext_gem_init(mrb_state* mrb) 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()); diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 1565873a0..bca9b463a 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -43,6 +43,18 @@ assert('Proc#curry') do assert_raise(ArgumentError) { b.curry(1) } end +assert('Proc#parameters') do + assert_equal([], Proc.new {}.parameters) + assert_equal([], Proc.new {||}.parameters) + assert_equal([[:opt, :a]], Proc.new {|a|}.parameters) + assert_equal([[:req, :a]], lambda {|a|}.parameters) + assert_equal([[:opt, :a]], lambda {|a=nil|}.parameters) + assert_equal([[:req, :a]], ->(a){}.parameters) + assert_equal([[:rest, :a]], Proc.new {|*a|}.parameters) + assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], Proc.new {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) + assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) +end + assert('Proc#to_proc') do proc = Proc.new {} assert_equal proc, proc.to_proc |
