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

ruby-changes:26212

From: shugo <ko1@a...>
Date: Sat, 8 Dec 2012 11:37:28 +0900 (JST)
Subject: [ruby-changes:26212] shugo:r38269 (trunk): * eval.c (rb_mod_refine), vm_eval.c (rb_yield_refine_block):

shugo	2012-12-08 11:37:16 +0900 (Sat, 08 Dec 2012)

  New Revision: 38269

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

  Log:
    * eval.c (rb_mod_refine), vm_eval.c (rb_yield_refine_block):
      Module#refine activates all refinements defined in that module
      only in a given block.
    
    * string.c (sym_to_proc, sym_call): don't use refinements.
    
    * test/ruby/test_refinement.rb: related test.

  Modified files:
    trunk/ChangeLog
    trunk/eval.c
    trunk/include/ruby/ruby.h
    trunk/string.c
    trunk/test/ruby/test_refinement.rb
    trunk/vm_eval.c

Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 38268)
+++ include/ruby/ruby.h	(revision 38269)
@@ -1333,8 +1333,6 @@
 VALUE rb_funcall2(VALUE, ID, int, const VALUE*);
 VALUE rb_funcall3(VALUE, ID, int, const VALUE*);
 VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*);
-VALUE rb_funcall_passing_block_with_refinements(VALUE, ID, int,
-						const VALUE*, VALUE);
 int rb_scan_args(int, const VALUE*, const char*, ...);
 VALUE rb_call_super(int, const VALUE*);
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 38268)
+++ ChangeLog	(revision 38269)
@@ -1,3 +1,13 @@
+Sat Dec  8 11:17:53 2012  Shugo Maeda  <shugo@r...>
+
+	* eval.c (rb_mod_refine), vm_eval.c (rb_yield_refine_block): 
+	  Module#refine activates all refinements defined in that module
+	  only in a given block.
+
+	* string.c (sym_to_proc, sym_call): don't use refinements.
+
+	* test/ruby/test_refinement.rb: related test.
+
 Sat Dec  8 09:24:42 2012  Eric Hodel  <drbrain@s...>
 
 	* ext/openssl/ossl_x509name.c:  Completed documentation for
Index: string.c
===================================================================
--- string.c	(revision 38268)
+++ string.c	(revision 38269)
@@ -14,8 +14,7 @@
 #include "ruby/ruby.h"
 #include "ruby/re.h"
 #include "ruby/encoding.h"
-#include "node.h"
-#include "eval_intern.h"
+#include "vm_core.h"
 #include "internal.h"
 #include "probes.h"
 #include <assert.h>
@@ -7862,18 +7861,15 @@
 }
 
 static VALUE
-sym_call(VALUE args, VALUE p, int argc, VALUE *argv)
+sym_call(VALUE args, VALUE sym, int argc, VALUE *argv)
 {
     VALUE obj;
-    NODE *memo = RNODE(p);
 
     if (argc < 1) {
 	rb_raise(rb_eArgError, "no receiver given");
     }
     obj = argv[0];
-    return rb_funcall_passing_block_with_refinements(obj, (ID) memo->u1.id,
-						     argc - 1, argv + 1,
-						     memo->u2.value);
+    return rb_funcall_passing_block(obj, (ID)sym, argc - 1, argv + 1);
 }
 
 /*
@@ -7893,32 +7889,25 @@
     VALUE proc;
     long id, index;
     VALUE *aryp;
-    const NODE *cref = rb_vm_cref();
 
+    if (!sym_proc_cache) {
+	sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2);
+	rb_gc_register_mark_object(sym_proc_cache);
+	rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil);
+    }
+
     id = SYM2ID(sym);
-    if (NIL_P(cref->nd_refinements)) {
-	if (!sym_proc_cache) {
-	    sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2);
-	    rb_gc_register_mark_object(sym_proc_cache);
-	    rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil);
-	}
+    index = (id % SYM_PROC_CACHE_SIZE) << 1;
 
-	index = (id % SYM_PROC_CACHE_SIZE) << 1;
-	aryp = RARRAY_PTR(sym_proc_cache);
-	if (aryp[index] == sym) {
-	    return aryp[index + 1];
-	}
-	else {
-	    proc = rb_proc_new(sym_call,
-			       (VALUE) NEW_MEMO(id, Qnil, 0));
-	    aryp[index] = sym;
-	    aryp[index + 1] = proc;
-	    return proc;
-	}
+    aryp = RARRAY_PTR(sym_proc_cache);
+    if (aryp[index] == sym) {
+	return aryp[index + 1];
     }
     else {
-	return rb_proc_new(sym_call,
-			   (VALUE) NEW_MEMO(id, cref->nd_refinements, 0));
+	proc = rb_proc_new(sym_call, (VALUE)id);
+	aryp[index] = sym;
+	aryp[index + 1] = proc;
+	return proc;
     }
 }
 
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 38268)
+++ vm_eval.c	(revision 38269)
@@ -784,30 +784,6 @@
     return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
 }
 
-VALUE
-rb_funcall_passing_block_with_refinements(VALUE recv, ID mid, int argc,
-					  const VALUE *argv,
-					  VALUE refinements)
-{
-    VALUE defined_class;
-    rb_method_entry_t *me =
-	rb_search_method_entry(recv, mid, &defined_class);
-    rb_thread_t *th;
-    int call_status;
-
-    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
-	me = rb_resolve_refined_method(refinements, me, &defined_class);
-    }
-    PASS_PASSED_BLOCK_TH(GET_THREAD());
-    th = GET_THREAD();
-    call_status = rb_method_call_status(th, me, CALL_PUBLIC, th->cfp->self);
-    if (call_status != NOEX_OK) {
-	return method_missing(recv, mid, argc, argv, call_status);
-    }
-    stack_check();
-    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
-}
-
 static VALUE
 send_internal(int argc, const VALUE *argv, VALUE recv, call_type scope)
 {
@@ -1462,6 +1438,25 @@
     }
 }
 
+VALUE
+rb_yield_refine_block(VALUE refinement, VALUE refinements)
+{
+    rb_thread_t *th = GET_THREAD();
+    rb_block_t block, *blockptr;
+    NODE *cref;
+
+    if ((blockptr = VM_CF_BLOCK_PTR(th->cfp)) != 0) {
+	block = *blockptr;
+	block.self = refinement;
+	VM_CF_LEP(th->cfp)[0] = VM_ENVVAL_BLOCK_PTR(&block);
+    }
+    cref = vm_cref_push(th, refinement, NOEX_PUBLIC, blockptr);
+    cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL;
+    cref->nd_refinements = refinements;
+
+    return vm_yield_with_cref(th, 0, NULL, cref);
+}
+
 /* string eval under the class/module context */
 static VALUE
 eval_under(VALUE under, VALUE self, VALUE src, const char *file, int line)
Index: eval.c
===================================================================
--- eval.c	(revision 38268)
+++ eval.c	(revision 38269)
@@ -1148,6 +1148,38 @@
     return result;
 }
 
+static void
+add_activated_refinement(VALUE activated_refinements,
+			 VALUE klass, VALUE refinement)
+{
+    VALUE iclass, c, superclass = klass;
+
+    if (!NIL_P(c = rb_hash_lookup(activated_refinements, klass))) {
+	superclass = c;
+	while (c && TYPE(c) == T_ICLASS) {
+	    if (RBASIC(c)->klass == refinement) {
+		/* already used refinement */
+		return;
+	    }
+	    c = RCLASS_SUPER(c);
+	}
+    }
+    FL_SET(refinement, RMODULE_IS_OVERLAID);
+    c = iclass = rb_include_class_new(refinement, superclass);
+    RCLASS_REFINED_CLASS(c) = klass;
+    refinement = RCLASS_SUPER(refinement);
+    while (refinement) {
+	FL_SET(refinement, RMODULE_IS_OVERLAID);
+	c = RCLASS_SUPER(c) =
+	    rb_include_class_new(refinement, RCLASS_SUPER(c));
+	RCLASS_REFINED_CLASS(c) = klass;
+	refinement = RCLASS_SUPER(refinement);
+    }
+    rb_hash_aset(activated_refinements, klass, iclass);
+}
+
+VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements);
+
 /*
  *  call-seq:
  *     refine(klass) { block }   -> module
@@ -1160,10 +1192,10 @@
 static VALUE
 rb_mod_refine(VALUE module, VALUE klass)
 {
-    NODE *cref = rb_vm_cref();
-    VALUE mod;
-    ID id_refinements, id_refined_class, id_defined_at;
-    VALUE refinements;
+    VALUE refinement;
+    ID id_refinements, id_activated_refinements,
+       id_refined_class, id_defined_at;
+    VALUE refinements, activated_refinements;
 
     if (!rb_block_given_p()) {
         rb_raise(rb_eArgError, "no block given");
@@ -1175,21 +1207,28 @@
 	refinements = hidden_identity_hash_new();
 	rb_ivar_set(module, id_refinements, refinements);
     }
-    mod = rb_hash_lookup(refinements, klass);
-    if (NIL_P(mod)) {
-	mod = rb_module_new();
-	FL_SET(mod, RMODULE_IS_REFINEMENT);
+    CONST_ID(id_activated_refinements, "__activated_refinements__");
+    activated_refinements = rb_attr_get(module, id_activated_refinements);
+    if (NIL_P(activated_refinements)) {
+	activated_refinements = hidden_identity_hash_new();
+	rb_ivar_set(module, id_activated_refinements,
+		    activated_refinements);
+    }
+    refinement = rb_hash_lookup(refinements, klass);
+    if (NIL_P(refinement)) {
+	refinement = rb_module_new();
+	FL_SET(refinement, RMODULE_IS_REFINEMENT);
 	CONST_ID(id_refined_class, "__refined_class__");
-	rb_ivar_set(mod, id_refined_class, klass);
+	rb_ivar_set(refinement, id_refined_class, klass);
 	CONST_ID(id_defined_at, "__defined_at__");
-	rb_ivar_set(mod, id_defined_at, module);
-	rb_define_singleton_method(mod, "include",
+	rb_ivar_set(refinement, id_defined_at, module);
+	rb_define_singleton_method(refinement, "include",
 				   refinement_module_include, -1);
-	rb_using_refinement(cref, klass, mod);
-	rb_hash_aset(refinements, klass, mod);
+	rb_hash_aset(refinements, klass, refinement);
+	add_activated_refinement(activated_refinements, klass, refinement);
     }
-    rb_mod_module_eval(0, NULL, mod);
-    return mod;
+    rb_yield_refine_block(refinement, activated_refinements);
+    return refinement;
 }
 
 static int
Index: test/ruby/test_refinement.rb
===================================================================
--- test/ruby/test_refinement.rb	(revision 38268)
+++ test/ruby/test_refinement.rb	(revision 38269)
@@ -463,33 +463,6 @@
     assert_equal("no block given", e.message)
   end
 
-  module SymbolToProc
-    class C
-    end
-
-    module M
-      refine C do
-        def foo
-          "foo"
-        end
-      end
-
-      def self.call_foo
-        c = C.new
-        :foo.to_proc.call(c)
-      end
-
-      def self.foo_proc
-        :foo.to_proc
-      end
-    end
-  end
-
-  def test_symbol_to_proc
-    assert_equal("foo", SymbolToProc::M.call_foo)
-    assert_equal("foo", SymbolToProc::M.foo_proc.call(SymbolToProc::C.new))
-  end
-
   module Inspect
     module M
       refine Fixnum do
@@ -584,6 +557,65 @@
     end
   end
 
+  module RefineScoping
+    refine String do
+      def foo
+        "foo"
+      end
+
+      def RefineScoping.call_in_refine_block
+        "".foo
+      end
+    end
+
+    def self.call_outside_refine_block
+      "".foo
+    end
+  end
+
+  def test_refine_scoping
+    assert_equal("foo", RefineScoping.call_in_refine_block)
+    assert_raise(NoMethodError) do
+      RefineScoping.call_outside_refine_block
+    end
+  end
+
+  module StringRecursiveLength
+    refine String do
+      def recursive_length
+        if empty?
+          0
+        else 
+          self[1..-1].recursive_length + 1
+        end
+      end
+    end
+  end
+
+  def test_refine_recursion
+    x = eval_using(StringRecursiveLength, "'foo'.recursive_length")
+    assert_equal(3, x)
+  end
+
+  module ToJSON
+    refine Integer do
+      def to_json; to_s; end
+    end
+
+    refine Array do
+      def to_json; "[" + map { |i| i.to_json }.join(",") + "]" end
+    end
+
+    refine Hash do
+      def to_json; "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}" end
+    end
+  end
+
+  def test_refine_mutual_recursion
+    x = eval_using(ToJSON, "[{1=>2}, {3=>4}].to_json")
+    assert_equal('[{"1":2},{"3":4}]', x)
+  end
+
   private
 
   def eval_using(mod, s)

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

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