[前][次][番号順一覧][スレッド一覧]

ruby-changes:40863

From: nobu <ko1@a...>
Date: Tue, 8 Dec 2015 14:27:20 +0900 (JST)
Subject: [ruby-changes:40863] nobu:r52942 (trunk): error.c: name_err_local_variables

nobu	2015-12-08 14:27:10 +0900 (Tue, 08 Dec 2015)

  New Revision: 52942

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52942

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

  Modified files:
    trunk/ChangeLog
    trunk/error.c
    trunk/iseq.c
    trunk/iseq.h
    trunk/test/ruby/test_exception.rb
    trunk/vm.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52941)
+++ ChangeLog	(revision 52942)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Dec  8 14:27:07 2015  Nobuyoshi Nakada  <nobu@r...>
+
+	* 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@r...>
 
 	* marshal.c (w_objivar): skip internal instance variables in
Index: iseq.c
===================================================================
--- iseq.c	(revision 52941)
+++ iseq.c	(revision 52942)
@@ -2319,6 +2319,12 @@ rb_iseqw_line_trace_specify(VALUE iseqva https://github.com/ruby/ruby/blob/trunk/iseq.c#L2319
     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
  *
Index: iseq.h
===================================================================
--- iseq.h	(revision 52941)
+++ iseq.h	(revision 52942)
@@ -214,6 +214,9 @@ enum defined_type { https://github.com/ruby/ruby/blob/trunk/iseq.h#L214
 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 */
Index: error.c
===================================================================
--- error.c	(revision 52941)
+++ error.c	(revision 52942)
@@ -35,6 +35,9 @@ https://github.com/ruby/ruby/blob/trunk/error.c#L35
 #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; https://github.com/ruby/ruby/blob/trunk/error.c#L663
 
 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 https://github.com/ruby/ruby/blob/trunk/error.c#L1105
 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;
 }
 
@@ -1123,6 +1134,30 @@ name_err_name(VALUE self) https://github.com/ruby/ruby/blob/trunk/error.c#L1134
 }
 
 /*
+ *  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) https://github.com/ruby/ruby/blob/trunk/error.c#L1977
     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) https://github.com/ruby/ruby/blob/trunk/error.c#L2010
     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
Index: vm.c
===================================================================
--- vm.c	(revision 52941)
+++ vm.c	(revision 52942)
@@ -755,6 +755,17 @@ rb_vm_env_local_variables(const rb_env_t https://github.com/ruby/ruby/blob/trunk/vm.c#L755
     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
Index: test/ruby/test_exception.rb
===================================================================
--- test/ruby/test_exception.rb	(revision 52941)
+++ test/ruby/test_exception.rb	(revision 52942)
@@ -688,6 +688,16 @@ end.join https://github.com/ruby/ruby/blob/trunk/test/ruby/test_exception.rb#L688
     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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]