/*
 *  call-seq:
 *     obj.method_missing(symbol [, *args] )   => result
 *  
 *  Invoked by Ruby when <i>obj</i> is sent a message it cannot handle.
 *  <i>symbol</i> is the symbol for the method called, and <i>args</i>
 *  are any arguments that were passed to it. By default, the interpreter
 *  raises an error when this method is called. However, it is possible
 *  to override the method to provide more dynamic behavior.
 *  The example below creates
 *  a class <code>Roman</code>, which responds to methods with names
 *  consisting of roman numerals, returning the corresponding integer
 *  values.
 *     
 *     class Roman
 *       def romanToInt(str)
 *         # ...
 *       end
 *       def method_missing(methId)
 *         str = methId.id2name
 *         romanToInt(str)
 *       end
 *     end
 *     
 *     r = Roman.new
 *     r.iv      #=> 4
 *     r.xxiii   #=> 23
 *     r.mm      #=> 2000
 */

static VALUE
rb_method_missing(argc, argv, obj)
    int argc;
    VALUE *argv;
    VALUE obj;
{
    ID id;
    VALUE exc = rb_eNoMethodError;
    char *format = 0;
    NODE *cnode = ruby_current_node;

    if (argc == 0 || !SYMBOL_P(argv[0])) {
        rb_raise(rb_eArgError, "no id given");
    }

    stack_check();

    id = SYM2ID(argv[0]);

    if (last_call_status & CSTAT_PRIV) {
        format = "private method `%s' called for %s";
    }
    else if (last_call_status & CSTAT_PROT) {
        format = "protected method `%s' called for %s";
    }
    else if (last_call_status & CSTAT_VCALL) {
        format = "undefined local variable or method `%s' for %s";
        exc = rb_eNameError;
    }
    else if (last_call_status & CSTAT_SUPER) {
        format = "super: no superclass method `%s'";
    }
    if (!format) {
        format = "undefined method `%s' for %s";
    }

    ruby_current_node = cnode;
    {
        int n = 0;
        VALUE args[3];

        args[n++] = rb_funcall(rb_const_get(exc, rb_intern("message")), '!',
                               3, rb_str_new2(format), obj, argv[0]);
        args[n++] = argv[0];
        if (exc == rb_eNoMethodError) {
            args[n++] = rb_ary_new4(argc-1, argv+1);
        }
        exc = rb_class_new_instance(n, args, exc);
        ruby_frame = ruby_frame->prev; /* pop frame for "method_missing" */
        rb_exc_raise(exc);
    }

    return Qnil;                /* not reached */
}