nested_methods-r29944-20101127.diff
| b/bootstraptest/test_method.rb | ||
|---|---|---|
| 287 | 287 |
assert_equal '1', %q( class C |
| 288 | 288 |
def m |
| 289 | 289 |
def mm() 1 end |
| 290 |
mm |
|
| 290 | 291 |
end |
| 291 | 292 |
end |
| 292 |
C.new.m |
|
| 293 |
C.new.mm ) |
|
| 293 |
C.new.m ) |
|
| 294 | 294 |
assert_equal '1', %q( class C |
| 295 | 295 |
def m |
| 296 | 296 |
def mm() 1 end |
| 297 |
mm |
|
| 297 | 298 |
end |
| 298 | 299 |
end |
| 299 |
instance_eval "C.new.m; C.new.mm" )
|
|
| 300 |
instance_eval "C.new.m" ) |
|
| 300 | 301 | |
| 301 | 302 |
# method_missing |
| 302 | 303 |
assert_equal ':m', %q( class C |
| b/compile.c | ||
|---|---|---|
| 4575 | 4575 |
ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE)); |
| 4576 | 4576 |
ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid)); |
| 4577 | 4577 |
ADD_INSN1(ret, nd_line(node), putiseq, iseqval); |
| 4578 |
ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(3)); |
|
| 4578 |
ADD_INSN1(ret, nd_line(node), putobject, |
|
| 4579 |
node->flags & NODE_FL_NESTED_DEF ? Qtrue : Qfalse); |
|
| 4580 |
ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(4)); |
|
| 4579 | 4581 | |
| 4580 | 4582 |
if (poped) {
|
| 4581 | 4583 |
ADD_INSN(ret, nd_line(node), pop); |
| b/include/ruby/ruby.h | ||
|---|---|---|
| 630 | 630 |
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m) |
| 631 | 631 |
#define RMODULE_SUPER(m) RCLASS_SUPER(m) |
| 632 | 632 |
#define RMODULE_IS_OVERLAYED FL_USER2 |
| 633 |
#define RMODULE_HAS_NESTED_METHODS FL_USER3 |
|
| 633 | 634 | |
| 634 | 635 |
struct RFloat {
|
| 635 | 636 |
struct RBasic basic; |
| b/node.h | ||
|---|---|---|
| 269 | 269 |
#define NODE_FL_NEWLINE (((VALUE)1)<<7) |
| 270 | 270 |
#define NODE_FL_CREF_PUSHED_BY_EVAL NODE_FL_NEWLINE |
| 271 | 271 |
#define NODE_FL_CREF_OMOD_SHARED (((VALUE)1)<<6) |
| 272 |
#define NODE_FL_NESTED_DEF NODE_FL_CREF_OMOD_SHARED |
|
| 272 | 273 | |
| 273 | 274 |
#define NODE_TYPESHIFT 8 |
| 274 | 275 |
#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT) |
| b/parse.y | ||
|---|---|---|
| 2967 | 2967 |
reduce_nodes(&body); |
| 2968 | 2968 |
$$ = NEW_DEFN($2, $4, body, NOEX_PRIVATE); |
| 2969 | 2969 |
nd_set_line($$, $<num>1); |
| 2970 |
if (in_def > 1 || in_single > 0) |
|
| 2971 |
$$->flags |= NODE_FL_NESTED_DEF; |
|
| 2970 | 2972 |
/*% |
| 2971 | 2973 |
$$ = dispatch3(def, $2, $4, $5); |
| 2972 | 2974 |
%*/ |
| b/test/rdoc/test_rdoc_text.rb | ||
|---|---|---|
| 62 | 62 |
assert_equal expected, flush_left(text) |
| 63 | 63 |
end |
| 64 | 64 | |
| 65 |
def formatter() RDoc::Markup::ToHtml.new end |
|
| 65 | 66 |
def test_markup |
| 66 |
def formatter() RDoc::Markup::ToHtml.new end |
|
| 67 | 67 | |
| 68 | 68 |
assert_equal "<p>\nhi\n</p>\n", markup('hi')
|
| 69 | 69 |
end |
| b/test/ruby/test_nested_method.rb | ||
|---|---|---|
| 1 |
require 'test/unit' |
|
| 2 | ||
| 3 |
class TestNestedMethod < Test::Unit::TestCase |
|
| 4 |
def call_nested_method |
|
| 5 |
def foo |
|
| 6 |
return "foo" |
|
| 7 |
end |
|
| 8 | ||
| 9 |
return foo |
|
| 10 |
end |
|
| 11 | ||
| 12 |
def test_nested_method |
|
| 13 |
assert_equal("foo", call_nested_method)
|
|
| 14 |
assert_raise(NoMethodError) { foo() }
|
|
| 15 |
end |
|
| 16 | ||
| 17 |
def test_doubly_nested_method |
|
| 18 |
def call_doubly_nested_method |
|
| 19 |
def foo |
|
| 20 |
return "foo" |
|
| 21 |
end |
|
| 22 | ||
| 23 |
return foo |
|
| 24 |
end |
|
| 25 | ||
| 26 |
assert_equal("foo", call_doubly_nested_method)
|
|
| 27 |
assert_raise(NoMethodError) { foo() }
|
|
| 28 |
end |
|
| 29 |
end |
|
| b/vm.c | ||
|---|---|---|
| 1822 | 1822 |
return self; |
| 1823 | 1823 |
} |
| 1824 | 1824 | |
| 1825 |
static VALUE |
|
| 1826 |
find_module_for_nested_methods(NODE *cref, VALUE klass) |
|
| 1827 |
{
|
|
| 1828 |
VALUE iclass; |
|
| 1829 | ||
| 1830 |
if (NIL_P(cref->nd_omod)) |
|
| 1831 |
return Qnil; |
|
| 1832 |
iclass = rb_hash_lookup(cref->nd_omod, klass); |
|
| 1833 |
if (NIL_P(iclass)) |
|
| 1834 |
return Qnil; |
|
| 1835 |
while (iclass) {
|
|
| 1836 |
VALUE module = RBASIC(iclass)->klass; |
|
| 1837 |
if (FL_TEST(module, RMODULE_HAS_NESTED_METHODS)) {
|
|
| 1838 |
return module; |
|
| 1839 |
} |
|
| 1840 |
iclass = RCLASS_SUPER(iclass); |
|
| 1841 |
} |
|
| 1842 |
return Qnil; |
|
| 1843 |
} |
|
| 1844 | ||
| 1825 | 1845 |
VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase); |
| 1826 | 1846 | |
| 1827 | 1847 |
static void |
| 1828 |
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, |
|
| 1848 |
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, VALUE nested,
|
|
| 1829 | 1849 |
rb_num_t is_singleton, NODE *cref) |
| 1830 | 1850 |
{
|
| 1831 | 1851 |
VALUE klass = cref->nd_clss; |
| 1852 |
VALUE target, defined_class; |
|
| 1853 |
rb_method_entry_t *me; |
|
| 1832 | 1854 |
int noex = (int)cref->nd_visi; |
| 1855 |
int is_nested = RTEST(nested); |
|
| 1833 | 1856 |
rb_iseq_t *miseq; |
| 1834 | 1857 |
GetISeqPtr(iseqval, miseq); |
| 1835 | 1858 | |
| ... | ... | |
| 1854 | 1877 |
noex = NOEX_PUBLIC; |
| 1855 | 1878 |
} |
| 1856 | 1879 | |
| 1880 |
if (is_nested && th->cfp->lfp == th->cfp->dfp) {
|
|
| 1881 |
VALUE c; |
|
| 1882 |
if (TYPE(klass) == T_MODULE) {
|
|
| 1883 |
c = rb_obj_class(th->cfp->self); |
|
| 1884 |
} |
|
| 1885 |
else {
|
|
| 1886 |
c = klass; |
|
| 1887 |
} |
|
| 1888 |
if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
|
|
| 1889 |
target = Qnil; |
|
| 1890 |
} |
|
| 1891 |
else {
|
|
| 1892 |
target = find_module_for_nested_methods(cref, c); |
|
| 1893 |
} |
|
| 1894 |
if (NIL_P(target)) {
|
|
| 1895 |
target = rb_module_new(); |
|
| 1896 |
FL_SET(target, RMODULE_HAS_NESTED_METHODS); |
|
| 1897 |
rb_overlay_module(cref, c, target); |
|
| 1898 |
} |
|
| 1899 |
else {
|
|
| 1900 |
me = search_method(target, id, Qnil, &defined_class); |
|
| 1901 |
if (me && me->def->type == VM_METHOD_TYPE_ISEQ && |
|
| 1902 |
me->def->body.iseq == miseq) {
|
|
| 1903 |
return; |
|
| 1904 |
} |
|
| 1905 |
} |
|
| 1906 |
noex = NOEX_PRIVATE; |
|
| 1907 |
} |
|
| 1908 |
else {
|
|
| 1909 |
target = klass; |
|
| 1910 |
} |
|
| 1857 | 1911 |
/* dup */ |
| 1858 | 1912 |
COPY_CREF(miseq->cref_stack, cref); |
| 1859 | 1913 |
miseq->cref_stack->nd_visi = NOEX_PUBLIC; |
| 1860 |
miseq->klass = klass;
|
|
| 1914 |
miseq->klass = target;
|
|
| 1861 | 1915 |
miseq->defined_method_id = id; |
| 1862 |
rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
|
|
| 1916 |
rb_add_method(target, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
|
|
| 1863 | 1917 | |
| 1864 | 1918 |
if (!is_singleton && noex == NOEX_MODFUNC) {
|
| 1865 | 1919 |
rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC); |
| ... | ... | |
| 1873 | 1927 |
} while (0) |
| 1874 | 1928 | |
| 1875 | 1929 |
static VALUE |
| 1876 |
m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval) |
|
| 1930 |
m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval, VALUE nested)
|
|
| 1877 | 1931 |
{
|
| 1878 | 1932 |
REWIND_CFP({
|
| 1879 |
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref()); |
|
| 1933 |
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, nested, 0, rb_vm_cref());
|
|
| 1880 | 1934 |
}); |
| 1881 | 1935 |
return Qnil; |
| 1882 | 1936 |
} |
| ... | ... | |
| 1885 | 1939 |
m_core_define_singleton_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval) |
| 1886 | 1940 |
{
|
| 1887 | 1941 |
REWIND_CFP({
|
| 1888 |
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref()); |
|
| 1942 |
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, Qfalse, 1, rb_vm_cref());
|
|
| 1889 | 1943 |
}); |
| 1890 | 1944 |
return Qnil; |
| 1891 | 1945 |
} |
| ... | ... | |
| 2001 | 2055 |
rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3); |
| 2002 | 2056 |
rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2); |
| 2003 | 2057 |
rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2); |
| 2004 |
rb_define_method_id(klass, id_core_define_method, m_core_define_method, 3);
|
|
| 2058 |
rb_define_method_id(klass, id_core_define_method, m_core_define_method, 4);
|
|
| 2005 | 2059 |
rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3); |
| 2006 | 2060 |
rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1); |
| 2007 | 2061 |
rb_obj_freeze(fcore); |
| b/vm_core.h | ||
|---|---|---|
| 717 | 717 |
} \ |
| 718 | 718 |
} while (0) |
| 719 | 719 | |
| 720 |
void rb_overlay_module(NODE*, VALUE, VALUE); |
|
| 721 | ||
| 720 | 722 |
#if defined __GNUC__ && __GNUC__ >= 4 |
| 721 | 723 |
#pragma GCC visibility push(default) |
| 722 | 724 |
#endif |
| b/vm_method.c | ||
|---|---|---|
| 711 | 711 |
} |
| 712 | 712 | |
| 713 | 713 |
if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
|
| 714 |
VALUE mod = rb_module_new(); |
|
| 715 |
rb_overlay_module(cref, klass, mod); |
|
| 716 |
klass = mod; |
|
| 714 |
if (FL_TEST(me->klass, RMODULE_HAS_NESTED_METHODS)) {
|
|
| 715 |
klass = me->klass; |
|
| 716 |
} |
|
| 717 |
else {
|
|
| 718 |
VALUE mod = rb_module_new(); |
|
| 719 |
rb_overlay_module(cref, klass, mod); |
|
| 720 |
klass = mod; |
|
| 721 |
} |
|
| 717 | 722 |
} |
| 718 | 723 |
rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC); |
| 719 | 724 | |