/* -*- c -*-                    */
/* do not use C++ style comment */
/*                              */

MACRO macro_eval_invoke_method(recv, klass, id, num, mn, blockptr)
{
    /* method missing */
    if (mn == 0) {
	/* temporarily */
	if (id == idMethodMissing) {
	    rb_bug("method missing");
	}
	else {
	    int stat = 0;
	    if (flag & VM_CALL_VCALL_BIT) {
		stat |= NOEX_VCALL;
	    }
	    if (flag & VM_CALL_SUPER_BIT) {
		stat |= NOEX_SUPER;
	    }
	    val = eval_method_missing(th, id, recv, num, blockptr, stat);
	}
    }
    else if (!(flag & VM_CALL_FCALL_BIT) &&
	     (mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) {
	int stat = NOEX_PRIVATE;
	if (flag & VM_CALL_VCALL_BIT) {
	    stat |= NOEX_VCALL;
	}
	val = eval_method_missing(th, id, recv, num, blockptr, stat);
    }
    else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) {
	VALUE defined_class = mn->nd_clss;

	if (TYPE(defined_class) == T_ICLASS) {
	    defined_class = RBASIC(defined_class)->klass;
	}
	if (!rb_obj_is_kind_of(GET_SELF(), rb_class_real(defined_class))) {
	    val =
		eval_method_missing(th, id, recv, num, blockptr,
				    NOEX_PROTECTED);
	}
	else {
	    goto INSN_LABEL(normal_method_dispatch);
	}
    }
    else {
	NODE *node;
	INSN_LABEL(normal_method_dispatch):

	node = mn->nd_body;
	switch (nd_type(node)) {
	  case RUBY_VM_METHOD_NODE:{
	      vm_setup_method(th, GET_CFP(), num, blockptr, flag, (VALUE)node->nd_body, recv, klass);
	      RESTORE_REGS();
	      NEXT_INSN();
	  }
	  case NODE_CFUNC:{
	      val = vm_call_cfunc(th, GET_CFP(), num, id, recv, klass, node, blockptr);
	      break;
	  }
	  case NODE_ATTRSET:{
	      val = rb_ivar_set(recv, node->nd_vid, TOPN(0));
	      POPN(2);
	      break;
	  }
	  case NODE_IVAR:{
	      val = rb_ivar_get(recv, node->nd_vid);
	      POP();
	      break;
	  }
	  case NODE_BMETHOD:{
	      VALUE *argv = GET_SP() - num;
	      val = th_invoke_bmethod(th, id, node->nd_cval,
				      recv, klass, num, argv);
	      INC_SP(-num-1);
	      break;
	  }
	  case NODE_ZSUPER:{
	      klass = RCLASS(mn->nd_clss)->super;
	      mn = rb_method_node(klass, id);

	      if (mn != 0) {
		  goto INSN_LABEL(normal_method_dispatch);
	      }
	      else {
		  goto LABEL_IS_SC(start_method_dispatch);
	      }
	  }
	  default:{
	      printf("node: %s\n", ruby_node_name(nd_type(node)));
	      rb_bug("eval_invoke_method: unreachable");
	      /* unreachable */
	      break;
	  }
	}
    }
}

