error.c: name_err_local_variables

* error.c (name_err_local_variables): new method
  NameError#local_variables for internal use only.
  [Feature #11777]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52942 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2015-12-08 05:27:10 +00:00
Родитель cb3b463a50
Коммит 506b25aabf
6 изменённых файлов: 75 добавлений и 1 удалений

Просмотреть файл

@ -1,3 +1,9 @@
Tue Dec 8 14:27:07 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* error.c (name_err_local_variables): new method
NameError#local_variables for internal use only.
[Feature #11777]
Tue Dec 8 14:20:38 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* marshal.c (w_objivar): skip internal instance variables in

40
error.c
Просмотреть файл

@ -35,6 +35,9 @@
#define WEXITSTATUS(status) (status)
#endif
VALUE rb_iseqw_local_variables(VALUE iseqval);
VALUE rb_iseqw_new(const rb_iseq_t *);
VALUE rb_eEAGAIN;
VALUE rb_eEWOULDBLOCK;
VALUE rb_eEINPROGRESS;
@ -660,7 +663,7 @@ static VALUE rb_eNOERROR;
static ID id_new, id_cause, id_message, id_backtrace;
static ID id_name, id_args, id_Errno, id_errno, id_i_path;
static ID id_receiver;
static ID id_receiver, id_iseq, id_local_variables;
extern ID ruby_static_id_status;
#define id_bt idBt
#define id_bt_locations idBt_locations
@ -1102,10 +1105,18 @@ static VALUE
name_err_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE name;
VALUE iseqw = Qnil;
name = (argc > 1) ? argv[--argc] : Qnil;
rb_call_super(argc, argv);
rb_ivar_set(self, id_name, name);
{
rb_thread_t *th = GET_THREAD();
rb_control_frame_t *cfp =
rb_vm_get_ruby_level_next_cfp(th, RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp));
if (cfp) iseqw = rb_iseqw_new(cfp->iseq);
}
rb_ivar_set(self, id_iseq, iseqw);
return self;
}
@ -1122,6 +1133,30 @@ name_err_name(VALUE self)
return rb_attr_get(self, id_name);
}
/*
* call-seq:
* name_error.local_variables -> array
*
* Return a list of the local variable names defined where this
* NameError exception was raised.
*
* Internal use only.
*/
static VALUE
name_err_local_variables(VALUE self)
{
VALUE vars = rb_attr_get(self, id_local_variables);
if (NIL_P(vars)) {
VALUE iseqw = rb_attr_get(self, id_iseq);
if (!NIL_P(iseqw)) vars = rb_iseqw_local_variables(iseqw);
if (NIL_P(vars)) vars = rb_ary_new();
rb_ivar_set(self, id_local_variables, vars);
}
return vars;
}
/*
* call-seq:
* NoMethodError.new(msg, name [, args]) -> no_method_error
@ -1942,6 +1977,7 @@ Init_Exception(void)
rb_define_method(rb_eNameError, "initialize", name_err_initialize, -1);
rb_define_method(rb_eNameError, "name", name_err_name, 0);
rb_define_method(rb_eNameError, "receiver", name_err_receiver, 0);
rb_define_method(rb_eNameError, "local_variables", name_err_local_variables, 0);
rb_cNameErrorMesg = rb_define_class_under(rb_eNameError, "message", rb_cData);
rb_define_method(rb_cNameErrorMesg, "==", name_err_mesg_equal, 1);
rb_define_method(rb_cNameErrorMesg, "to_str", name_err_mesg_to_str, 0);
@ -1974,9 +2010,11 @@ Init_Exception(void)
id_name = rb_intern_const("name");
id_args = rb_intern_const("args");
id_receiver = rb_intern_const("receiver");
id_local_variables = rb_intern_const("local_variables");
id_Errno = rb_intern_const("Errno");
id_errno = rb_intern_const("errno");
id_i_path = rb_intern_const("@path");
id_iseq = rb_make_internal_id();
}
void

6
iseq.c
Просмотреть файл

@ -2319,6 +2319,12 @@ rb_iseqw_line_trace_specify(VALUE iseqval, VALUE pos, VALUE set)
return data.prev == 1 ? Qtrue : Qfalse;
}
VALUE
rb_iseqw_local_variables(VALUE iseqval)
{
return rb_iseq_local_variables(iseqw_check(iseqval));
}
/*
* Document-class: RubyVM::InstructionSequence
*

3
iseq.h
Просмотреть файл

@ -214,6 +214,9 @@ enum defined_type {
VALUE rb_iseq_defined_string(enum defined_type type);
void rb_iseq_make_compile_option(struct rb_compile_option_struct *option, VALUE opt);
/* vm.c */
VALUE rb_iseq_local_variables(const rb_iseq_t *iseq);
RUBY_SYMBOL_EXPORT_END
#endif /* RUBY_ISEQ_H */

Просмотреть файл

@ -688,6 +688,16 @@ end.join
assert_equal(:foo, e.name)
assert_equal([1, 2], e.args)
assert_same(obj, e.receiver)
def obj.test(a, b=nil, *c, &d)
e = a
1.times {|f| g = foo}
end
e = assert_raise(NameError) {
obj.test(3)
}
assert_equal(:foo, e.name)
assert_same(obj, e.receiver)
assert_equal(%i[a b c d e f g], e.local_variables.sort)
end
def test_output_string_encoding

11
vm.c
Просмотреть файл

@ -755,6 +755,17 @@ rb_vm_env_local_variables(const rb_env_t *env)
return local_var_list_finish(&vars);
}
VALUE
rb_iseq_local_variables(const rb_iseq_t *iseq)
{
struct local_var_list vars;
local_var_list_init(&vars);
while (collect_local_variables_in_iseq(iseq, &vars)) {
iseq = iseq->body->parent_iseq;
}
return local_var_list_finish(&vars);
}
/* Proc */
static inline VALUE