Hi,

At Mon, 20 Jan 2003 15:49:27 +0900,
Yukihiro Matsumoto wrote:
> Interesting idea, but I feel like they are responsibility of Binding,
> not Symbol.  For example,
> 
>   b = binding()
>   b.bind(:a, 2)
>   b.value(:a)

Tried.

--- Binding#bind(symbol, value)
    symbol is
    * local (block or function level) variable if already
      exists, attr_writer if defined, or new dynamic variable.
    * instance variable
    * class variable

--- Binding#value(symbol)
    symbol is
    * local variable if exists, or attr_reader.
    * instance variable
    * class variable

Constants and global variables are not implemented.  Required?


Index: eval.c =================================================================== RCS file: /cvs/ruby/src/ruby/eval.c,v retrieving revision 1.386 diff -u -2 -p -r1.386 eval.c --- eval.c 16 Jan 2003 07:38:39 -0000 1.386 +++ eval.c 20 Jan 2003 09:15:53 -0000 @@ -1609,7 +1609,8 @@ ev_const_get(cref, id, self) static VALUE -cvar_cbase() +cvar_cbase_in(frame) + struct FRAME *frame; { - NODE *cref = RNODE(ruby_frame->cbase); + NODE *cref = RNODE(frame->cbase); while (cref && cref->nd_next && FL_TEST(cref->nd_clss, FL_SINGLETON)) { @@ -1622,4 +1623,6 @@ cvar_cbase() } +#define cvar_cbase() cvar_cbase_in(ruby_frame) + static VALUE rb_mod_nesting() @@ -6412,4 +6415,114 @@ bind_clone(self) } +static VALUE * +bind_lvar(data, id) + struct BLOCK *data; + ID id; +{ + struct RVarmap *vars = data->dyna_vars; + struct SCOPE *scope = data->scope; + ID *tbl = scope->local_tbl; + + for (; vars; vars = vars->next) { + if (vars->id == id) { + return &vars->val; + } + } + if (tbl && scope->local_vars) { + long i, n = *tbl++; + for (i = 0; i < n; ++i) { + if (tbl[i] == id) { + return &scope->local_vars[i]; + } + } + } + return NULL; +} + +static VALUE +bind_value(self, sym) + VALUE self, sym; +{ + ID id = rb_to_id(sym); + struct BLOCK *data; + + Data_Get_Struct(self, struct BLOCK, data); + if (rb_is_local_id(id)) { + volatile int iter; + int state; + VALUE val, *vp; + + if ((vp = bind_lvar(data, id))) return *vp; + iter = ruby_frame->iter; + ruby_frame->iter = ITER_NOT; + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { + val = rb_funcall2(data->self, id, 0, 0); + } + POP_TAG(); + ruby_frame->iter = iter; + if (state) JUMP_TAG(state); + return val; + } + else if (rb_is_instance_id(id)) { + return rb_ivar_get(data->self, id); + } + else if (rb_is_class_id(id)) { + return rb_cvar_get(cvar_cbase_in(&data->frame), id); + } + else { + rb_raise(rb_eArgError, "invalid variable name: %s", rb_id2name(id)); + } + return Qnil; /* not reached */ +} + +static VALUE +bind_assign(self, sym, val) + VALUE self, sym, val; +{ + ID id = rb_to_id(sym); + struct BLOCK *data; + + Data_Get_Struct(self, struct BLOCK, data); + if (rb_is_local_id(id)) { + ID setter; + VALUE *vp = bind_lvar(data, id); + + if (vp) { + *vp = val; + return self; + } + else if (rb_respond_to(data->self, setter = rb_id_attrset(id))) { + volatile int iter = ruby_frame->iter; + int state; + ruby_frame->iter = ITER_NOT; + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { + rb_funcall2(data->self, id, 1, &val); + } + POP_TAG(); + ruby_frame->iter = iter; + if (state) JUMP_TAG(state); + } + else if (!data->dyna_vars) { + data->dyna_vars = new_dvar(id, val, 0); + if (data->scope == ruby_scope) ruby_dyna_vars = data->dyna_vars; + } + else { + data->dyna_vars->next = new_dvar(id, val, data->dyna_vars->next); + } + } + else if (rb_is_instance_id(id)) { + rb_ivar_set(data->self, id, val); + } + else if (rb_is_class_id(id)) { + rb_cvar_set(cvar_cbase_in(&data->frame), id, val, Qtrue); + } + else { + rb_raise(rb_eArgError, "invalid variable name: %s", rb_id2name(id)); + } + return self; +} + static VALUE rb_f_binding(self) @@ -7292,4 +7405,8 @@ Init_Proc() rb_undef_method(CLASS_OF(rb_cBinding), "new"); rb_define_method(rb_cBinding, "clone", bind_clone, 0); + rb_define_method(rb_cBinding, "value", bind_value, 1); + rb_define_method(rb_cBinding, "bind", bind_assign, 2); + rb_define_method(rb_cBinding, "[]", bind_value, 1); + rb_define_method(rb_cBinding, "[]=", bind_assign, 2); rb_cMethod = rb_define_class("Method", rb_cObject);
-- Nobu Nakada