summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-proc-ext/src/proc.c
diff options
context:
space:
mode:
authorksss <[email protected]>2014-06-25 15:55:59 +0900
committerksss <[email protected]>2014-06-25 16:05:33 +0900
commit9cafc5e1051765d67d451f4b456996300ddf355c (patch)
treea641137ba26861a6be1d3ad43ebb2ab405228de4 /mrbgems/mruby-proc-ext/src/proc.c
parentd4e49c9f8fe752e8f7d3d6b9dc10a55307654dfd (diff)
downloadmruby-9cafc5e1051765d67d451f4b456996300ddf355c.tar.gz
mruby-9cafc5e1051765d67d451f4b456996300ddf355c.zip
Implement Proc#parameters
Diffstat (limited to 'mrbgems/mruby-proc-ext/src/proc.c')
-rw-r--r--mrbgems/mruby-proc-ext/src/proc.c69
1 files changed, 69 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());