Feature #4085 » refinement-r29837-20101124.diff
bootstraptest/test_method.rb | ||
---|---|---|
assert_equal '1', %q( class C
|
||
def m
|
||
def mm() 1 end
|
||
mm
|
||
end
|
||
end
|
||
C.new.m
|
||
C.new.mm )
|
||
C.new.m )
|
||
assert_equal '1', %q( class C
|
||
def m
|
||
def mm() 1 end
|
||
mm
|
||
end
|
||
end
|
||
instance_eval "C.new.m; C.new.mm" )
|
||
instance_eval "C.new.m" )
|
||
# method_missing
|
||
assert_equal ':m', %q( class C
|
class.c | ||
---|---|---|
return module;
|
||
}
|
||
static VALUE
|
||
include_class_new(VALUE module, VALUE super)
|
||
VALUE
|
||
rb_include_class_new(VALUE module, VALUE super)
|
||
{
|
||
VALUE klass = class_alloc(T_ICLASS, rb_cClass);
|
||
... | ... | |
break;
|
||
}
|
||
}
|
||
c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c));
|
||
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
|
||
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
|
||
changed = 1;
|
||
skip:
|
||
... | ... | |
int
|
||
rb_obj_basic_to_s_p(VALUE obj)
|
||
{
|
||
const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"));
|
||
const rb_method_entry_t *me = rb_method_entry(CLASS_OF(obj), rb_intern("to_s"), 0);
|
||
if (me && me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
|
||
me->def->body.cfunc.func == rb_any_to_s)
|
||
return 1;
|
compile.c | ||
---|---|---|
ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
|
||
ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid));
|
||
ADD_INSN1(ret, nd_line(node), putiseq, iseqval);
|
||
ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(3));
|
||
ADD_INSN1(ret, nd_line(node), putobject,
|
||
node->flags & NODE_FL_NESTED_DEF ? Qtrue : Qfalse);
|
||
ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(4));
|
||
if (poped) {
|
||
ADD_INSN(ret, nd_line(node), pop);
|
eval.c | ||
---|---|---|
VALUE rb_binding_new(void);
|
||
NORETURN(void rb_raise_jump(VALUE));
|
||
NODE *rb_vm_get_cref(const rb_iseq_t *, const VALUE *, const VALUE *);
|
||
ID rb_frame_callee(void);
|
||
VALUE rb_eLocalJumpError;
|
||
VALUE rb_eSysStackError;
|
||
... | ... | |
}
|
||
void
|
||
rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
|
||
{
|
||
VALUE iclass, c, superclass = klass;
|
||
Check_Type(klass, T_CLASS);
|
||
Check_Type(module, T_MODULE);
|
||
if (NIL_P(cref->nd_omod)) {
|
||
cref->nd_omod = rb_hash_new();
|
||
rb_funcall(cref->nd_omod, rb_intern("compare_by_identity"), 0);
|
||
}
|
||
else {
|
||
if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
|
||
cref->nd_omod = rb_hash_dup(cref->nd_omod);
|
||
cref->flags &= ~NODE_FL_CREF_OMOD_SHARED;
|
||
}
|
||
if (!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
|
||
superclass = c;
|
||
while (c && TYPE(c) == T_ICLASS) {
|
||
if (RBASIC(c)->klass == module) {
|
||
/* already overlayed module */
|
||
return;
|
||
}
|
||
c = RCLASS_SUPER(c);
|
||
}
|
||
}
|
||
}
|
||
FL_SET(module, RMODULE_IS_OVERLAYED);
|
||
c = iclass = rb_include_class_new(module, superclass);
|
||
module = RCLASS_SUPER(module);
|
||
while (module) {
|
||
FL_SET(module, RMODULE_IS_OVERLAYED);
|
||
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
|
||
module = RCLASS_SUPER(module);
|
||
}
|
||
rb_hash_aset(cref->nd_omod, klass, iclass);
|
||
rb_clear_cache_by_class(klass);
|
||
}
|
||
static int
|
||
using_module_i(VALUE klass, VALUE module, VALUE arg)
|
||
{
|
||
NODE *cref = (NODE *) arg;
|
||
int i;
|
||
rb_overlay_module(cref, klass, module);
|
||
return ST_CONTINUE;
|
||
}
|
||
void
|
||
rb_using_module(NODE *cref, VALUE module)
|
||
{
|
||
ID id_overlayed_modules;
|
||
VALUE overlayed_modules;
|
||
Check_Type(module, T_MODULE);
|
||
CONST_ID(id_overlayed_modules, "__overlayed_modules__");
|
||
overlayed_modules = rb_attr_get(module, id_overlayed_modules);
|
||
if (NIL_P(overlayed_modules)) return;
|
||
rb_hash_foreach(overlayed_modules, using_module_i, (VALUE) cref);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* using(module) -> self
|
||
*
|
||
* Import class refinements from <i>module</i> into the receiver.
|
||
*/
|
||
static VALUE
|
||
rb_mod_using(VALUE self, VALUE module)
|
||
{
|
||
NODE *cref = rb_vm_cref();
|
||
ID id_using_modules;
|
||
VALUE using_modules;
|
||
CONST_ID(id_using_modules, "__using_modules__");
|
||
using_modules = rb_attr_get(self, id_using_modules);
|
||
if (NIL_P(using_modules)) {
|
||
using_modules = rb_hash_new();
|
||
rb_funcall(using_modules, rb_intern("compare_by_identity"), 0);
|
||
rb_ivar_set(self, id_using_modules, using_modules);
|
||
}
|
||
rb_hash_aset(using_modules, module, Qtrue);
|
||
rb_using_module(cref, module);
|
||
rb_funcall(module, rb_intern("used"), 1, self);
|
||
return self;
|
||
}
|
||
void rb_redefine_opt_method(VALUE, ID);
|
||
static VALUE
|
||
refinement_module_method_added(VALUE mod, VALUE mid)
|
||
{
|
||
ID id = SYM2ID(mid);
|
||
ID id_refined_class;
|
||
VALUE klass;
|
||
CONST_ID(id_refined_class, "__refined_class__");
|
||
klass = rb_ivar_get(mod, id_refined_class);
|
||
rb_redefine_opt_method(klass, id);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* refine(klass) { block } -> self
|
||
*
|
||
* Refine <i>klass</i> in the receiver.
|
||
*/
|
||
static VALUE
|
||
rb_mod_refine(VALUE module, VALUE klass)
|
||
{
|
||
NODE *cref = rb_vm_cref();
|
||
VALUE mod;
|
||
ID id_overlayed_modules, id_refined_class;
|
||
VALUE overlayed_modules, modules;
|
||
Check_Type(klass, T_CLASS);
|
||
CONST_ID(id_overlayed_modules, "__overlayed_modules__");
|
||
overlayed_modules = rb_attr_get(module, id_overlayed_modules);
|
||
if (NIL_P(overlayed_modules)) {
|
||
overlayed_modules = rb_hash_new();
|
||
rb_funcall(overlayed_modules, rb_intern("compare_by_identity"), 0);
|
||
rb_ivar_set(module, id_overlayed_modules, overlayed_modules);
|
||
}
|
||
mod = rb_hash_aref(overlayed_modules, klass);
|
||
if (NIL_P(mod)) {
|
||
mod = rb_module_new();
|
||
CONST_ID(id_refined_class, "__refined_class__");
|
||
rb_ivar_set(mod, id_refined_class, klass);
|
||
rb_define_singleton_method(mod, "method_added",
|
||
refinement_module_method_added, 1);
|
||
rb_overlay_module(cref, klass, mod);
|
||
rb_hash_aset(overlayed_modules, klass, mod);
|
||
}
|
||
rb_mod_module_eval(0, NULL, mod);
|
||
return mod;
|
||
}
|
||
void
|
||
rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
|
||
{
|
||
PASS_PASSED_BLOCK();
|
||
... | ... | |
return rb_mod_include(argc, argv, rb_cObject);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* using(module) -> self
|
||
*
|
||
* Import class refinements from <i>module</i> into the scope where <code>use</code> is called.
|
||
*/
|
||
static VALUE
|
||
f_using(VALUE self, VALUE module)
|
||
{
|
||
NODE *cref = rb_vm_cref();
|
||
rb_using_module(cref, module);
|
||
return self;
|
||
}
|
||
VALUE rb_f_trace_var();
|
||
VALUE rb_f_untrace_var();
|
||
... | ... | |
rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
|
||
rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
|
||
rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
|
||
rb_define_private_method(rb_cModule, "using", rb_mod_using, 1);
|
||
rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1);
|
||
rb_undef_method(rb_cClass, "module_function");
|
||
... | ... | |
rb_define_singleton_method(rb_vm_top_self(), "include", top_include, -1);
|
||
rb_define_global_function("using", f_using, 1);
|
||
rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
|
||
rb_define_global_function("trace_var", rb_f_trace_var, -1); /* in variable.c */
|
gc.c | ||
---|---|---|
ptr = (VALUE)obj->as.node.u2.node;
|
||
goto again;
|
||
case NODE_CREF:
|
||
gc_mark(objspace, obj->as.node.u0.value, lev);
|
||
gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
|
||
ptr = (VALUE)obj->as.node.u3.node;
|
||
goto again;
|
||
default: /* unlisted NODE */
|
||
if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) {
|
||
gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
|
include/ruby/intern.h | ||
---|---|---|
VALUE rb_make_metaclass(VALUE, VALUE);
|
||
void rb_check_inheritable(VALUE);
|
||
VALUE rb_class_inherited(VALUE, VALUE);
|
||
VALUE rb_mod_opened(VALUE);
|
||
VALUE rb_define_class_id(ID, VALUE);
|
||
VALUE rb_define_class_id_under(VALUE, ID, VALUE);
|
||
VALUE rb_module_new(void);
|
||
VALUE rb_define_module_id(ID);
|
||
VALUE rb_define_module_id_under(VALUE, ID);
|
||
VALUE rb_include_class_new(VALUE, VALUE);
|
||
VALUE rb_mod_included_modules(VALUE);
|
||
VALUE rb_mod_include_p(VALUE, VALUE);
|
||
VALUE rb_mod_ancestors(VALUE);
|
include/ruby/ruby.h | ||
---|---|---|
#define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m)
|
||
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
|
||
#define RMODULE_SUPER(m) RCLASS_SUPER(m)
|
||
#define RMODULE_HAS_NESTED_METHODS FL_USER2
|
||
#define RMODULE_IS_OVERLAYED FL_USER3
|
||
struct RFloat {
|
||
struct RBasic basic;
|
insns.def | ||
---|---|---|
()
|
||
(VALUE val)
|
||
{
|
||
NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
val = rb_cvar_get(vm_get_cvar_base(cref), id);
|
||
NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
val = rb_cvar_get(vm_get_cvar_base(cref, GET_CFP()), id);
|
||
}
|
||
/**
|
||
... | ... | |
(VALUE val)
|
||
()
|
||
{
|
||
NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
rb_cvar_set(vm_get_cvar_base(cref), id, val);
|
||
NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
||
rb_cvar_set(vm_get_cvar_base(cref, GET_CFP()), id, val);
|
||
}
|
||
/**
|
||
... | ... | |
break;
|
||
case DEFINED_METHOD:{
|
||
VALUE klass = CLASS_OF(v);
|
||
const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj));
|
||
const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0);
|
||
if (me) {
|
||
if (!(me->flag & NOEX_PRIVATE)) {
|
||
... | ... | |
/* enter scope */
|
||
vm_push_frame(th, class_iseq,
|
||
VM_FRAME_MAGIC_CLASS, klass, (VALUE) GET_BLOCK_PTR(),
|
||
VM_FRAME_MAGIC_CLASS, klass, 0, (VALUE) GET_BLOCK_PTR(),
|
||
class_iseq->iseq_encoded, GET_SP(), 0,
|
||
class_iseq->local_size);
|
||
rb_vm_using_modules(class_iseq->cref_stack, klass);
|
||
RESTORE_REGS();
|
||
INC_VM_STATE_VERSION();
|
||
... | ... | |
(VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
|
||
{
|
||
const rb_method_entry_t *me;
|
||
VALUE recv, klass;
|
||
VALUE recv, klass, defined_class;
|
||
rb_block_t *blockptr = 0;
|
||
VALUE flag = op_flag;
|
||
int num = caller_setup_args(th, GET_CFP(), flag, (int)op_argc,
|
||
... | ... | |
/* get receiver */
|
||
recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num);
|
||
klass = CLASS_OF(recv);
|
||
me = vm_method_search(id, klass, ic);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
||
me = vm_method_search(id, klass, ic, &defined_class);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class);
|
||
}
|
||
/**
|
||
... | ... | |
VALUE recv, klass;
|
||
ID id;
|
||
const rb_method_entry_t *me;
|
||
rb_iseq_t *ip;
|
||
flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||
recv = GET_SELF();
|
||
vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
|
||
/* temporary measure for [Bug #2402] [Bug #2502] [Bug #3136] */
|
||
if (!rb_obj_is_kind_of(recv, klass)) {
|
||
rb_raise(rb_eNotImpError, "super from singleton method that is defined to multiple classes is not supported; this will be fixed in 1.9.3 or later");
|
||
ip = GET_ISEQ();
|
||
while (ip && !ip->klass) {
|
||
ip = ip->parent_iseq;
|
||
}
|
||
me = rb_method_entry(klass, id, &klass);
|
||
if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
|
||
me->def->body.iseq == ip) {
|
||
klass = RCLASS_SUPER(klass);
|
||
me = rb_method_entry_get_with_omod(Qnil, klass, id, &klass);
|
||
}
|
||
me = rb_method_entry(klass, id);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
||
CALL_METHOD(num, blockptr, flag, id, me, recv, klass);
|
||
}
|
||
/**
|
||
... | ... | |
(VALUE val)
|
||
{
|
||
extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
|
||
const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic);
|
||
const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic, 0);
|
||
val = Qundef;
|
||
if (check_cfunc(me, rb_obj_not_equal)) {
|
||
... | ... | |
(VALUE val)
|
||
{
|
||
extern VALUE rb_obj_not(VALUE obj);
|
||
const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic);
|
||
const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic, 0);
|
||
if (check_cfunc(me, rb_obj_not)) {
|
||
val = RTEST(recv) ? Qfalse : Qtrue;
|
iseq.c | ||
---|---|---|
/* set class nest stack */
|
||
if (type == ISEQ_TYPE_TOP) {
|
||
/* toplevel is private */
|
||
iseq->cref_stack = NEW_BLOCK(rb_cObject);
|
||
iseq->cref_stack->nd_file = 0;
|
||
iseq->cref_stack = NEW_CREF(rb_cObject);
|
||
iseq->cref_stack->nd_omod = Qnil;
|
||
iseq->cref_stack->nd_visi = NOEX_PRIVATE;
|
||
if (th->top_wrapper) {
|
||
NODE *cref = NEW_BLOCK(th->top_wrapper);
|
||
cref->nd_file = 0;
|
||
NODE *cref = NEW_CREF(th->top_wrapper);
|
||
cref->nd_omod = Qnil;
|
||
cref->nd_visi = NOEX_PRIVATE;
|
||
cref->nd_next = iseq->cref_stack;
|
||
iseq->cref_stack = cref;
|
||
}
|
||
}
|
||
else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
|
||
iseq->cref_stack = NEW_BLOCK(0); /* place holder */
|
||
iseq->cref_stack->nd_file = 0;
|
||
iseq->cref_stack = NEW_CREF(0); /* place holder */
|
||
iseq->cref_stack->nd_omod = Qnil;
|
||
}
|
||
else if (RTEST(parent)) {
|
||
rb_iseq_t *piseq;
|
||
... | ... | |
iseq1->local_iseq = iseq1;
|
||
}
|
||
if (newcbase) {
|
||
iseq1->cref_stack = NEW_BLOCK(newcbase);
|
||
iseq1->cref_stack = NEW_CREF(newcbase);
|
||
iseq1->cref_stack->nd_omod = iseq0->cref_stack->nd_omod;
|
||
iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
|
||
if (iseq0->cref_stack->nd_next) {
|
||
iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next;
|
||
}
|
lex.c.blt | ||
---|---|---|
/* C code produced by gperf version 3.0.4 */
|
||
/* Command-line: gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' defs/keywords */
|
||
/* C code produced by gperf version 3.0.3 */
|
||
/* Command-line: gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' ../defs/keywords */
|
||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||
... | ... | |
error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
|
||
#endif
|
||
#line 1 "defs/keywords"
|
||
#line 1 "../defs/keywords"
|
||
struct kwtable {const char *name; int id[2]; enum lex_state_e state;};
|
||
const struct kwtable *rb_reserved_word(const char *, unsigned int);
|
||
#ifndef RIPPER
|
||
static const struct kwtable *reserved_word(const char *, unsigned int);
|
||
#define rb_reserved_word(str, len) reserved_word(str, len)
|
||
#line 9 "defs/keywords"
|
||
#line 9 "../defs/keywords"
|
||
struct kwtable;
|
||
#define TOTAL_KEYWORDS 41
|
||
... | ... | |
#ifdef __GNUC__
|
||
__inline
|
||
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
|
||
#ifdef __GNUC_STDC_INLINE__
|
||
__attribute__ ((__gnu_inline__))
|
||
#endif
|
||
#endif
|
||
... | ... | |
static const struct kwtable wordlist[] =
|
||
{
|
||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||
#line 19 "defs/keywords"
|
||
#line 19 "../defs/keywords"
|
||
{"break", {keyword_break, keyword_break}, EXPR_MID},
|
||
#line 25 "defs/keywords"
|
||
#line 25 "../defs/keywords"
|
||
{"else", {keyword_else, keyword_else}, EXPR_BEG},
|
||
#line 35 "defs/keywords"
|
||
#line 35 "../defs/keywords"
|
||
{"nil", {keyword_nil, keyword_nil}, EXPR_END},
|
||
#line 28 "defs/keywords"
|
||
#line 28 "../defs/keywords"
|
||
{"ensure", {keyword_ensure, keyword_ensure}, EXPR_BEG},
|
||
#line 27 "defs/keywords"
|
||
#line 27 "../defs/keywords"
|
||
{"end", {keyword_end, keyword_end}, EXPR_END},
|
||
#line 44 "defs/keywords"
|
||
#line 44 "../defs/keywords"
|
||
{"then", {keyword_then, keyword_then}, EXPR_BEG},
|
||
#line 36 "defs/keywords"
|
||
#line 36 "../defs/keywords"
|
||
{"not", {keyword_not, keyword_not}, EXPR_ARG},
|
||
#line 29 "defs/keywords"
|
||
#line 29 "../defs/keywords"
|
||
{"false", {keyword_false, keyword_false}, EXPR_END},
|
||
#line 42 "defs/keywords"
|
||
#line 42 "../defs/keywords"
|
||
{"self", {keyword_self, keyword_self}, EXPR_END},
|
||
#line 26 "defs/keywords"
|
||
#line 26 "../defs/keywords"
|
||
{"elsif", {keyword_elsif, keyword_elsif}, EXPR_VALUE},
|
||
#line 39 "defs/keywords"
|
||
#line 39 "../defs/keywords"
|
||
{"rescue", {keyword_rescue, modifier_rescue}, EXPR_MID},
|
||
#line 45 "defs/keywords"
|
||
#line 45 "../defs/keywords"
|
||
{"true", {keyword_true, keyword_true}, EXPR_END},
|
||
#line 48 "defs/keywords"
|
||
#line 48 "../defs/keywords"
|
||
{"until", {keyword_until, modifier_until}, EXPR_VALUE},
|
||
#line 47 "defs/keywords"
|
||
#line 47 "../defs/keywords"
|
||
{"unless", {keyword_unless, modifier_unless}, EXPR_VALUE},
|
||
#line 41 "defs/keywords"
|
||
#line 41 "../defs/keywords"
|
||
{"return", {keyword_return, keyword_return}, EXPR_MID},
|
||
#line 22 "defs/keywords"
|
||
#line 22 "../defs/keywords"
|
||
{"def", {keyword_def, keyword_def}, EXPR_FNAME},
|
||
#line 17 "defs/keywords"
|
||
#line 17 "../defs/keywords"
|
||
{"and", {keyword_and, keyword_and}, EXPR_VALUE},
|
||
#line 24 "defs/keywords"
|
||
#line 24 "../defs/keywords"
|
||
{"do", {keyword_do, keyword_do}, EXPR_BEG},
|
||
#line 51 "defs/keywords"
|
||
#line 51 "../defs/keywords"
|
||
{"yield", {keyword_yield, keyword_yield}, EXPR_ARG},
|
||
#line 30 "defs/keywords"
|
||
#line 30 "../defs/keywords"
|
||
{"for", {keyword_for, keyword_for}, EXPR_VALUE},
|
||
#line 46 "defs/keywords"
|
||
#line 46 "../defs/keywords"
|
||
{"undef", {keyword_undef, keyword_undef}, EXPR_FNAME},
|
||
#line 37 "defs/keywords"
|
||
#line 37 "../defs/keywords"
|
||
{"or", {keyword_or, keyword_or}, EXPR_VALUE},
|
||
#line 32 "defs/keywords"
|
||
#line 32 "../defs/keywords"
|
||
{"in", {keyword_in, keyword_in}, EXPR_VALUE},
|
||
#line 49 "defs/keywords"
|
||
#line 49 "../defs/keywords"
|
||
{"when", {keyword_when, keyword_when}, EXPR_VALUE},
|
||
#line 40 "defs/keywords"
|
||
#line 40 "../defs/keywords"
|
||
{"retry", {keyword_retry, keyword_retry}, EXPR_END},
|
||
#line 31 "defs/keywords"
|
||
#line 31 "../defs/keywords"
|
||
{"if", {keyword_if, modifier_if}, EXPR_VALUE},
|
||
#line 20 "defs/keywords"
|
||
#line 20 "../defs/keywords"
|
||
{"case", {keyword_case, keyword_case}, EXPR_VALUE},
|
||
#line 38 "defs/keywords"
|
||
#line 38 "../defs/keywords"
|
||
{"redo", {keyword_redo, keyword_redo}, EXPR_END},
|
||
#line 34 "defs/keywords"
|
||
#line 34 "../defs/keywords"
|
||
{"next", {keyword_next, keyword_next}, EXPR_MID},
|
||
#line 43 "defs/keywords"
|
||
#line 43 "../defs/keywords"
|
||
{"super", {keyword_super, keyword_super}, EXPR_ARG},
|
||
#line 33 "defs/keywords"
|
||
#line 33 "../defs/keywords"
|
||
{"module", {keyword_module, keyword_module}, EXPR_VALUE},
|
||
#line 18 "defs/keywords"
|
||
#line 18 "../defs/keywords"
|
||
{"begin", {keyword_begin, keyword_begin}, EXPR_BEG},
|
||
#line 12 "defs/keywords"
|
||
#line 12 "../defs/keywords"
|
||
{"__LINE__", {keyword__LINE__, keyword__LINE__}, EXPR_END},
|
||
#line 13 "defs/keywords"
|
||
#line 13 "../defs/keywords"
|
||
{"__FILE__", {keyword__FILE__, keyword__FILE__}, EXPR_END},
|
||
#line 11 "defs/keywords"
|
||
#line 11 "../defs/keywords"
|
||
{"__ENCODING__", {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
|
||
#line 15 "defs/keywords"
|
||
#line 15 "../defs/keywords"
|
||
{"END", {keyword_END, keyword_END}, EXPR_END},
|
||
#line 16 "defs/keywords"
|
||
#line 16 "../defs/keywords"
|
||
{"alias", {keyword_alias, keyword_alias}, EXPR_FNAME},
|
||
#line 14 "defs/keywords"
|
||
#line 14 "../defs/keywords"
|
||
{"BEGIN", {keyword_BEGIN, keyword_BEGIN}, EXPR_END},
|
||
#line 23 "defs/keywords"
|
||
#line 23 "../defs/keywords"
|
||
{"defined?", {keyword_defined, keyword_defined}, EXPR_ARG},
|
||
#line 21 "defs/keywords"
|
||
#line 21 "../defs/keywords"
|
||
{"class", {keyword_class, keyword_class}, EXPR_CLASS},
|
||
{""}, {""},
|
||
#line 50 "defs/keywords"
|
||
#line 50 "../defs/keywords"
|
||
{"while", {keyword_while, modifier_while}, EXPR_VALUE}
|
||
};
|
||
... | ... | |
}
|
||
return 0;
|
||
}
|
||
#line 52 "defs/keywords"
|
||
#line 52 "../defs/keywords"
|
||
#endif
|
method.h | ||
---|---|---|
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
|
||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
|
||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
|
||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
|
||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id);
|
||
rb_method_entry_t *rb_method_entry_get_with_omod(VALUE omod, VALUE klass, ID id, VALUE *define_class_ptr);
|
||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *define_class_ptr);
|
||
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
|
||
int rb_method_entry_arity(const rb_method_entry_t *me);
|
node.h | ||
---|---|---|
#define NODE_COLON2 NODE_COLON2
|
||
NODE_COLON3,
|
||
#define NODE_COLON3 NODE_COLON3
|
||
NODE_CREF,
|
||
#define NODE_CREF NODE_CREF
|
||
NODE_DOT2,
|
||
#define NODE_DOT2 NODE_DOT2
|
||
NODE_DOT3,
|
||
... | ... | |
typedef struct RNode {
|
||
unsigned long flags;
|
||
char *nd_file;
|
||
union {
|
||
char *file;
|
||
VALUE value;
|
||
} u0;
|
||
union {
|
||
struct RNode *node;
|
||
ID id;
|
||
... | ... | |
#define RNODE(obj) (R_CAST(RNode)(obj))
|
||
/* 0..4:T_TYPES, 5:FL_MARK, 6:reserved, 7:NODE_FL_NEWLINE */
|
||
/* 0..4:T_TYPES, 5:FL_MARK, 6:NODE_FL_NESTED_DEF, 7:NODE_FL_NEWLINE */
|
||
#define NODE_FL_NEWLINE (((VALUE)1)<<7)
|
||
#define NODE_FL_NESTED_DEF (((VALUE)1)<<6)
|
||
#define NODE_FL_CREF_PUSHED_BY_EVAL NODE_FL_NEWLINE
|
||
#define NODE_FL_CREF_OMOD_SHARED NODE_FL_NESTED_DEF
|
||
#define NODE_TYPESHIFT 8
|
||
#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT)
|
||
... | ... | |
#define nd_set_line(n,l) \
|
||
RNODE(n)->flags=((RNODE(n)->flags&~(-1<<NODE_LSHIFT))|(((l)&NODE_LMASK)<<NODE_LSHIFT))
|
||
#define nd_file u0.file
|
||
#define nd_omod u0.value
|
||
#define nd_head u1.node
|
||
#define nd_alen u2.argc
|
||
#define nd_next u3.node
|
||
... | ... | |
#define NEW_MODULE(n,b) NEW_NODE(NODE_MODULE,n,NEW_SCOPE(0,b),0)
|
||
#define NEW_COLON2(c,i) NEW_NODE(NODE_COLON2,c,i,0)
|
||
#define NEW_COLON3(i) NEW_NODE(NODE_COLON3,0,i,0)
|
||
#define NEW_CREF(a) NEW_NODE(NODE_CREF,a,0,0)
|
||
#define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0)
|
||
#define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0)
|
||
#define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0)
|
object.c | ||
---|---|---|
rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1);
|
||
rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1);
|
||
rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1);
|
||
rb_define_private_method(rb_cModule, "used", rb_obj_dummy, 1);
|
||
rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1);
|
||
rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1);
|
||
rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1);
|
parse.y | ||
---|---|---|
reduce_nodes(&body);
|
||
$$ = NEW_DEFN($2, $4, body, NOEX_PRIVATE);
|
||
nd_set_line($$, $<num>1);
|
||
if (in_def > 1 || in_single > 0)
|
||
$$->flags |= NODE_FL_NESTED_DEF;
|
||
/*%
|
||
$$ = dispatch3(def, $2, $4, $5);
|
||
%*/
|
proc.c | ||
---|---|---|
struct METHOD {
|
||
VALUE recv;
|
||
VALUE rclass;
|
||
VALUE defined_class;
|
||
ID id;
|
||
rb_method_entry_t me;
|
||
};
|
||
... | ... | |
bm_mark(void *ptr)
|
||
{
|
||
struct METHOD *data = ptr;
|
||
rb_gc_mark(data->defined_class);
|
||
rb_gc_mark(data->rclass);
|
||
rb_gc_mark(data->recv);
|
||
rb_mark_method_entry(&data->me);
|
||
... | ... | |
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||
{
|
||
VALUE method;
|
||
VALUE rclass = klass;
|
||
VALUE rclass = klass, defined_class;
|
||
ID rid = id;
|
||
struct METHOD *data;
|
||
rb_method_entry_t *me, meb;
|
||
... | ... | |
rb_method_flag_t flag = NOEX_UNDEF;
|
||
again:
|
||
me = rb_method_entry(klass, id);
|
||
me = rb_method_entry(klass, id, &defined_class);
|
||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||
ID rmiss = rb_intern("respond_to_missing?");
|
||
VALUE sym = ID2SYM(id);
|
||
... | ... | |
}
|
||
}
|
||
if (def && def->type == VM_METHOD_TYPE_ZSUPER) {
|
||
klass = RCLASS_SUPER(me->klass);
|
||
klass = RCLASS_SUPER(defined_class);
|
||
id = def->original_id;
|
||
goto again;
|
||
}
|
||
klass = me->klass;
|
||
klass = defined_class;
|
||
while (rclass != klass &&
|
||
(FL_TEST(rclass, FL_SINGLETON) || TYPE(rclass) == T_ICLASS)) {
|
||
... | ... | |
data->recv = obj;
|
||
data->rclass = rclass;
|
||
data->defined_class = defined_class;
|
||
data->id = rid;
|
||
data->me = *me;
|
||
if (def) def->alias_count++;
|
||
... | ... | |
data->me = orig->me;
|
||
if (orig->me.def) orig->me.def->alias_count++;
|
||
data->rclass = orig->rclass;
|
||
data->defined_class = orig->defined_class;
|
||
OBJ_INFECT(method, obj);
|
||
return method;
|
||
... | ... | |
if ((state = EXEC_TAG()) == 0) {
|
||
rb_thread_t *th = GET_THREAD();
|
||
VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||
const rb_method_entry_t *me);
|
||
const rb_method_entry_t *me, VALUE defined_class);
|
||
PASS_PASSED_BLOCK_TH(th);
|
||
result = rb_vm_call(th, data->recv, data->id, argc, argv, &data->me);
|
||
result = rb_vm_call(th, data->recv, data->id, argc, argv, &data->me, data->defined_class);
|
||
}
|
||
POP_TAG();
|
||
if (safe >= 0)
|
||
... | ... | |
int
|
||
rb_mod_method_arity(VALUE mod, ID id)
|
||
{
|
||
rb_method_entry_t *me = rb_method_entry(mod, id);
|
||
rb_method_entry_t *me = rb_method_entry(mod, id, 0);
|
||
return rb_method_entry_arity(me);
|
||
}
|
||
test/rdoc/test_rdoc_text.rb | ||
---|---|---|
assert_equal expected, flush_left(text)
|
||
end
|
||
def formatter() RDoc::Markup::ToHtml.new end
|
||
def test_markup
|
||
def formatter() RDoc::Markup::ToHtml.new end
|
||
assert_equal "<p>\nhi\n</p>\n", markup('hi')
|
||
end
|
test/ruby/test_nested_method.rb | ||
---|---|---|
require 'test/unit'
|
||
class TestNestedMethod < Test::Unit::TestCase
|
||
def call_nested_method
|
||
def foo
|
||
return "foo"
|
||
end
|
||
return foo
|
||
end
|
||
def test_nested_method
|
||
assert_equal("foo", call_nested_method)
|
||
assert_raise(NoMethodError) { foo() }
|
||
end
|
||
def test_doubly_nested_method
|
||
def call_doubly_nested_method
|
||
def foo
|
||
return "foo"
|
||
end
|
||
return foo
|
||
end
|
||
assert_equal("foo", call_doubly_nested_method)
|
||
assert_raise(NoMethodError) { foo() }
|
||
end
|
||
end
|
test/ruby/test_refinement.rb | ||
---|---|---|
require 'test/unit'
|
||
class TestRefinement < Test::Unit::TestCase
|
||
class Foo
|
||
def x
|
||
return "Foo#x"
|
||
end
|
||
def y
|
||
return "Foo#y"
|
||
end
|
||
def call_x
|
||
return x
|
||
end
|
||
end
|
||
module FooExt
|
||
refine Foo do
|
||
def x
|
||
return "FooExt#x"
|
||
end
|
||
def y
|
||
return "FooExt#y " + super
|
||
end
|
||
def z
|
||
return "FooExt#z"
|
||
end
|
||
end
|
||
end
|
||
module FooExt2
|
||
refine Foo do
|
||
def x
|
||
return "FooExt2#x"
|
||
end
|
||
def y
|
||
return "FooExt2#y " + super
|
||
end
|
||
def z
|
||
return "FooExt2#z"
|
||
end
|
||
end
|
||
end
|
||
class FooSub < Foo
|
||
def x
|
||
return "FooSub#x"
|
||
end
|
||
def y
|
||
return "FooSub#y " + super
|
||
end
|
||
end
|
||
class FooExtClient
|
||
using FooExt
|
||
def self.invoke_x_on(foo)
|
||
return foo.x
|
||
end
|
||
def self.invoke_y_on(foo)
|
||
return foo.y
|
||
end
|
||
def self.invoke_z_on(foo)
|
||
return foo.z
|
||
end
|
||
def self.invoke_call_x_on(foo)
|
||
return foo.call_x
|
||
end
|
||
end
|
||
class FooExtClient2
|
||
using FooExt
|
||
using FooExt2
|
||
def self.invoke_y_on(foo)
|
||
return foo.y
|
||
end
|
||
end
|
||
def test_override
|
||
foo = Foo.new
|
||
assert_equal("Foo#x", foo.x)
|
||
assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo))
|
||
assert_equal("Foo#x", foo.x)
|
||
end
|
||
def test_super
|
||
foo = Foo.new
|
||
assert_equal("Foo#y", foo.y)
|
||
assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo))
|
||
assert_equal("Foo#y", foo.y)
|
||
end
|
||
def test_super_chain
|
||
foo = Foo.new
|
||
assert_equal("Foo#y", foo.y)
|
||
assert_equal("FooExt2#y FooExt#y Foo#y", FooExtClient2.invoke_y_on(foo))
|
||
assert_equal("Foo#y", foo.y)
|
||
end
|
||
def test_new_method
|
||
foo = Foo.new
|
||
assert_raise(NoMethodError) { foo.z }
|
||
assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo))
|
||
assert_raise(NoMethodError) { foo.z }
|
||
end
|
||
def test_no_local_rebinding
|
||
foo = Foo.new
|
||
assert_equal("Foo#x", foo.call_x)
|
||
assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo))
|
||
assert_equal("Foo#x", foo.call_x)
|
||
end
|
||
def test_subclass_is_prior
|
||
sub = FooSub.new
|
||
assert_equal("FooSub#x", sub.x)
|
||
assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
|
||
assert_equal("FooSub#x", sub.x)
|
||
end
|
||
def test_subclass_is_prior
|
||
sub = FooSub.new
|
||
assert_equal("FooSub#x", sub.x)
|
||
assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
|
||
assert_equal("FooSub#x", sub.x)
|
||
end
|
||
def test_super_in_subclass
|
||
sub = FooSub.new
|
||
assert_equal("FooSub#y Foo#y", sub.y)
|
||
# not "FooSub#y FooExt#y Foo#y"
|
||
assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub))
|
||
assert_equal("FooSub#y Foo#y", sub.y)
|
||
end
|
||
def test_new_method_on_subclass
|
||
sub = FooSub.new
|
||
assert_raise(NoMethodError) { sub.z }
|
||
assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub))
|
||
assert_raise(NoMethodError) { sub.z }
|
||
end
|
||
def test_module_eval
|
||
foo = Foo.new
|
||
assert_equal("Foo#x", foo.x)
|
||
assert_equal("FooExt#x", FooExt.module_eval { foo.x })
|
||
assert_equal("Foo#x", foo.x)
|
||
end
|
||
def test_instance_eval
|
||
foo = Foo.new
|
||
ext_client = FooExtClient.new
|
||
assert_equal("Foo#x", foo.x)
|
||
assert_equal("FooExt#x", ext_client.instance_eval { foo.x })
|
||
assert_equal("Foo#x", foo.x)
|
||
end
|
||
def test_override_builtin_method
|
||
m = Module.new {
|
||
refine Fixnum do
|
||
def /(other) quo(other) end
|
||
end
|
||
}
|
||
assert_equal(0, 1 / 2)
|
||
assert_equal(Rational(1, 2), m.module_eval { 1 / 2 })
|
||
assert_equal(0, 1 / 2)
|
||
end
|
||
def test_return_value_of_refine
|
||
mod = nil
|
||
result = nil
|
||
m = Module.new {
|
||
result = refine(Object) {
|
||
mod = self
|
||
}
|
||
}
|
||
assert_equal mod, result
|
||
end
|
||
def test_refine_same_class_twice
|
||
result1 = nil
|
||
result2 = nil
|
||
result3 = nil
|
||
m = Module.new {
|
||
result1 = refine(Fixnum) {
|
||
def foo; return "foo" end
|
||
}
|
||
result2 = refine(Fixnum) {
|
||
def bar; return "bar" end
|
||
}
|
||
result3 = refine(String) {
|
||
def baz; return "baz" end
|
||
}
|
||
}
|
||
assert_equal("foo", m.module_eval { 1.foo })
|
||
assert_equal("bar", m.module_eval { 1.bar })
|
||
assert_equal(result1, result2)
|
||
assert_not_equal(result1, result3)
|
||
end
|
||
end
|
vm.c | ||
---|---|---|
rb_vm_set_finish_env(rb_thread_t * th)
|
||
{
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_FINISH,
|
||
Qnil, th->cfp->lfp[0], 0,
|
||
Qnil, Qnil, th->cfp->lfp[0], 0,
|
||
th->cfp->sp, 0, 1);
|
||
th->cfp->pc = (VALUE *)&finish_insn_seq[0];
|
||
return Qtrue;
|
||
... | ... | |
rb_vm_set_finish_env(th);
|
||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP,
|
||
th->top_self, 0, iseq->iseq_encoded,
|
||
th->top_self, rb_cObject, 0, iseq->iseq_encoded,
|
||
th->cfp->sp, 0, iseq->local_size);
|
||
CHECK_STACK_OVERFLOW(th->cfp, iseq->stack_max);
|
||
... | ... | |
/* for return */
|
||
rb_vm_set_finish_env(th);
|
||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self,
|
||
vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL, block->self, block->klass,
|
||
GC_GUARDED_PTR(block->dfp), iseq->iseq_encoded,
|
||
th->cfp->sp, block->lfp, iseq->local_size);
|
||
... | ... | |
GetProcPtr(procval, proc);
|
||
proc->blockprocval = blockprocval;
|
||
proc->block.self = block->self;
|
||
proc->block.klass = block->klass;
|
||
proc->block.lfp = block->lfp;
|
||
proc->block.dfp = block->dfp;
|
||
proc->block.iseq = block->iseq;
|
||
... | ... | |
type == VM_FRAME_MAGIC_LAMBDA);
|
||
ncfp = vm_push_frame(th, iseq, type,
|
||
self, GC_GUARDED_PTR(block->dfp),
|
||
self, th->passed_defined_class,
|
||
GC_GUARDED_PTR(block->dfp),
|
||
iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, block->lfp,
|
||
iseq->local_size - arg_size);
|
||
th->passed_defined_class = 0;
|
||
ncfp->me = th->passed_me;
|
||
th->passed_me = 0;
|
||
th->passed_block = blockptr;
|
||
... | ... | |
{
|
||
rb_thread_t *th = GET_THREAD();
|
||
rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
|
||
return vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp);
|
||
if (!cfp) return NULL;
|
||
return rb_vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp);
|
||
}
|
||
#if 0
|
||
... | ... | |
/* push block frame */
|
||
cfp->sp[0] = err;
|
||
vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_BLOCK,
|
||
cfp->self, (VALUE)cfp->dfp, catch_iseq->iseq_encoded,
|
||
cfp->self, cfp->klass,
|
||
(VALUE)cfp->dfp, catch_iseq->iseq_encoded,
|
||
cfp->sp + 1 /* push value */, cfp->lfp, catch_iseq->local_size - 1);
|
||
state = 0;
|
||
... | ... | |
VALUE val;
|
||
vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP,
|
||
recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
recv, CLASS_OF(recv), (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
val = (*func)(arg);
|
||
... | ... | |
RUBY_MARK_UNLESS_NULL(th->root_fiber);
|
||
RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
|
||
RUBY_MARK_UNLESS_NULL(th->last_status);
|
||
RUBY_MARK_UNLESS_NULL(th->passed_defined_class);
|
||
RUBY_MARK_UNLESS_NULL(th->locking_mutex);
|
||
... | ... | |
th->cfp = (void *)(th->stack + th->stack_size);
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_TOP, Qnil, 0, 0,
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_TOP, Qnil, Qnil, 0, 0,
|
||
th->stack, 0, 1);
|
||
th->status = THREAD_RUNNABLE;
|
||
... | ... | |
return self;
|
||
}
|
||
static VALUE
|
||
find_module_for_nested_methods(NODE *cref, VALUE klass)
|
||
{
|
||
VALUE iclass;
|
||
if (NIL_P(cref->nd_omod))
|
||
return Qnil;
|
||
iclass = rb_hash_lookup(cref->nd_omod, klass);
|
||
if (NIL_P(iclass))
|
||
return Qnil;
|
||
while (iclass) {
|
||
VALUE module = RBASIC(iclass)->klass;
|
||
if (FL_TEST(module, RMODULE_HAS_NESTED_METHODS)) {
|
||
return module;
|
||
}
|
||
iclass = RCLASS_SUPER(iclass);
|
||
}
|
||
return Qnil;
|
||
}
|
||
VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase);
|
||
static void
|
||
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
|
||
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, VALUE nested,
|
||
rb_num_t is_singleton, NODE *cref)
|
||
{
|
||
VALUE klass = cref->nd_clss;
|
||
VALUE target, defined_class;
|
||
rb_method_entry_t *me;
|
||
int noex = (int)cref->nd_visi;
|
||
int is_nested = RTEST(nested);
|
||
rb_iseq_t *miseq;
|
||
GetISeqPtr(iseqval, miseq);
|
||
... | ... | |
noex = NOEX_PUBLIC;
|
||
}
|
||
if (is_nested && th->cfp->lfp == th->cfp->dfp) {
|
||
VALUE c;
|
||
if (TYPE(klass) == T_MODULE) {
|
||
c = rb_obj_class(th->cfp->self);
|
||
}
|
||
else {
|
||
c = klass;
|
||
}
|
||
if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
|
||
target = Qnil;
|
||
}
|
||
else {
|
||
target = find_module_for_nested_methods(cref, c);
|
||
}
|
||
if (NIL_P(target)) {
|
||
target = rb_module_new();
|
||
FL_SET(target, RMODULE_HAS_NESTED_METHODS);
|
||
rb_overlay_module(cref, c, target);
|
||
}
|
||
else {
|
||
me = search_method(target, id, Qnil, &defined_class);
|
||
if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
|
||
me->def->body.iseq == miseq) {
|
||
return;
|
||
}
|
||
}
|
||
noex = NOEX_PRIVATE;
|
||
}
|
||
else {
|
||
target = klass;
|
||
}
|
||
/* dup */
|
||
COPY_CREF(miseq->cref_stack, cref);
|
||
miseq->cref_stack->nd_visi = NOEX_PUBLIC;
|
||
miseq->klass = klass;
|
||
miseq->klass = target;
|
||
miseq->defined_method_id = id;
|
||
rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
|
||
rb_add_method(target, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
|
||
if (!is_singleton && noex == NOEX_MODFUNC) {
|
||
rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
|
||
... | ... | |
} while (0)
|
||
static VALUE
|
||
m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
|
||
m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval, VALUE nested)
|
||
{
|
||
REWIND_CFP({
|
||
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref());
|
||
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, nested, 0, rb_vm_cref());
|
||
});
|
||
return Qnil;
|
||
}
|
||
... | ... | |
m_core_define_singleton_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
|
||
{
|
||
REWIND_CFP({
|
||
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref());
|
||
vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, Qfalse, 1, rb_vm_cref());
|
||
});
|
||
return Qnil;
|
||
}
|
||
... | ... | |
rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
|
||
rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
|
||
rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2);
|
||
rb_define_method_id(klass, id_core_define_method, m_core_define_method, 3);
|
||
rb_define_method_id(klass, id_core_define_method, m_core_define_method, 4);
|
||
rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3);
|
||
rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1);
|
||
rb_obj_freeze(fcore);
|
vm_core.h | ||
---|---|---|
rb_method_entry_t *method;
|
||
long index;
|
||
} ic_value;
|
||
union {
|
||
VALUE defined_class;
|
||
} ic_value2;
|
||
};
|
||
#if 1
|
||
... | ... | |
VALUE *bp; /* cfp[2] */
|
||
rb_iseq_t *iseq; /* cfp[3] */
|
||
VALUE flag; /* cfp[4] */
|
||
VALUE self; /* cfp[5] / block[0] */
|
||
VALUE *lfp; /* cfp[6] / block[1] */
|
||
VALUE *dfp; /* cfp[7] / block[2] */
|
||
rb_iseq_t *block_iseq; /* cfp[8] / block[3] */
|
||
VALUE proc; /* cfp[9] / block[4] */
|
||
const rb_method_entry_t *me;/* cfp[10] */
|
||
VALUE self; /* cfp[5] / block[0] */
|
||
VALUE klass; /* cfp[6] / block[1] */
|
||
VALUE *lfp; /* cfp[7] / block[2] */
|
||
VALUE *dfp; /* cfp[8] / block[3] */
|
||
rb_iseq_t *block_iseq; /* cfp[9] / block[4] */
|
||
VALUE proc; /* cfp[10] / block[5] */
|
||
const rb_method_entry_t *me;/* cfp[11] */
|
||
} rb_control_frame_t;
|
||
typedef struct rb_block_struct {
|
||
VALUE self; /* share with method frame if it's only block */
|
||
VALUE klass; /* share with method frame if it's only block */
|
||
VALUE *lfp; /* share with method frame if it's only block */
|
||
VALUE *dfp; /* share with method frame if it's only block */
|
||
rb_iseq_t *iseq;
|
||
... | ... | |
/* for bmethod */
|
||
const rb_method_entry_t *passed_me;
|
||
VALUE passed_defined_class;
|
||
/* for load(true) */
|
||
VALUE top_self;
|
||
... | ... | |
} \
|
||
} while (0)
|
||
void rb_overlay_module(NODE*, VALUE, VALUE);
|
||
#if defined __GNUC__ && __GNUC__ >= 4
|
||
#pragma GCC visibility push(default)
|
||
#endif
|
vm_eval.c | ||
---|---|---|
static inline VALUE
|
||
vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||
const rb_method_entry_t *me)
|
||
const rb_method_entry_t *me, VALUE defined_class)
|
||
{
|
||
const rb_method_definition_t *def = me->def;
|
||
VALUE val;
|
||
VALUE klass = me->klass;
|
||
VALUE klass = defined_class;
|
||
const rb_block_t *blockptr = 0;
|
||
if (!def) return Qnil;
|
||
... | ... | |
*reg_cfp->sp++ = argv[i];
|
||
}
|
||
vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me);
|
||
vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me, klass);
|
||
val = vm_exec(th);
|
||
break;
|
||
}
|
||
... | ... | |
rb_control_frame_t *reg_cfp = th->cfp;
|
||
rb_control_frame_t *cfp =
|
||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||
recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
recv, klass, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||
cfp->me = me;
|
||
val = call_cfunc(def->body.cfunc.func, recv, def->body.cfunc.argc, argc, argv);
|
||
... | ... | |
break;
|
||
}
|
||
case VM_METHOD_TYPE_BMETHOD: {
|
||
val = vm_call_bmethod(th, recv, argc, argv, blockptr, me);
|
||
val = vm_call_bmethod(th, recv, argc, argv, blockptr, me, klass);
|
||
break;
|
||
}
|
||
case VM_METHOD_TYPE_ZSUPER: {
|
||
klass = RCLASS_SUPER(klass);
|
||
if (!klass || !(me = rb_method_entry(klass, id))) {
|
||
if (!klass || !(me = rb_method_entry(klass, id, &klass))) {
|
||
return method_missing(recv, id, argc, argv, NOEX_SUPER);
|
||
}
|
||
RUBY_VM_CHECK_INTS();
|
||
... | ... | |
VALUE
|
||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||
const rb_method_entry_t *me)
|
||
const rb_method_entry_t *me, VALUE defined_class)
|
||
{
|
||
return vm_call0(th, recv, id, argc, argv, me);
|
||
return vm_call0(th, recv, id, argc, argv, me, defined_class);
|
||
}
|
||
static inline VALUE
|
||
... | ... | |
rb_method_entry_t *me;
|
||
rb_control_frame_t *cfp = th->cfp;
|
||
if (!cfp->iseq) {
|
||
klass = cfp->me->klass;
|
||
klass = RCLASS_SUPER(klass);
|
||
if (!cfp->iseq && !NIL_P(cfp->klass)) {
|
||
klass = RCLASS_SUPER(cfp->klass);
|
||
if (klass == 0) {
|
||
klass = vm_search_normal_superclass(cfp->me->klass, recv);
|
||
... | ... | |
rb_bug("vm_call_super: should not be reached");
|
||
}
|
||
me = rb_method_entry(klass, id);
|
||
me = rb_method_entry(klass, id, &klass);
|
||
if (!me) {
|
||
return method_missing(recv, id, argc, argv, NOEX_SUPER);
|
||
}
|
||
return vm_call0(th, recv, id, argc, argv, me);
|
||
return vm_call0(th, recv, id, argc, argv, me, klass);
|
||
}
|
||
VALUE
|
||
... | ... | |
}
|
||
}
|
||
static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid);
|
||
static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
|
||
static inline int rb_method_call_status(rb_thread_t *th, rb_method_entry_t *me, call_type scope, VALUE self);
|
||
#define NOEX_OK NOEX_NOSUPER
|
||
... | ... | |
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
||
call_type scope, VALUE self)
|
||
{
|
||
rb_method_entry_t *me = rb_search_method_entry(recv, mid);
|
||
VALUE defined_class;
|
||
rb_method_entry_t *me = rb_search_method_entry(recv, mid, &defined_class);
|
||
rb_thread_t *th = GET_THREAD();
|
||
int call_status = rb_method_call_status(th, me, scope, self);
|
||
... | ... | |
return method_missing(recv, mid, argc, argv, call_status);
|
||
}
|
||
stack_check();
|
||
return vm_call0(th, recv, mid, argc, argv, me);
|
||
return vm_call0(th, recv, mid, argc, argv, me, defined_class);
|
||
}
|
||
struct rescue_funcall_args {
|
||
... | ... | |
static VALUE
|