/*
Copyright (C) 2003-2008, The Perl Foundation.
$Id: /mirror/trunk/src/pmc/delegate.pmc 29983 2008-08-02T22:45:13.271765Z allison  $

=head1 NAME

src/pmc/delegate.pmc - delegate PMC

=head1 DESCRIPTION

Delegate each and every function to parrot bytecode.

Almost all methods are auto-generated in lib/Parrot/Pmc2c.pm

=head2 Functions

=over 4

=cut

*/

#include "parrot/parrot.h"
#include "delegate.str"

/*

All these functions to run code can leak a full Parrot register file, as
well as potentially permanently unroot some PMCs or strings, if the
vtable method throws an exception. It really ought be caught rather than
let flow through.

*/

static void
vtable_meth_not_found(PARROT_INTERP, PMC *pmc, const char *meth)
{
    STRING *_class;

    if (PObj_is_class_TEST(pmc))
        _class = VTABLE_get_string(interp, get_attrib_num(
                (SLOTTYPE *)PMC_data(GET_CLASS(pmc)), PCD_CLASS_NAME));
    else
        _class = pmc->vtable->whoami;

    Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_VTABLE_NOT_FOUND,
        "Can't find vtable method '%s' in class '%Ss'", meth, _class);
}

pmclass delegate {

/*

=back

=head2 Methods

=over 4

=item C<PMC *instantiate(PMC *sig)>

Calls the delegated C<__instantiate> method if it exists.

RT#46701 Actually the PMC compiler should emit different code, if a method is
present in src/pmc/default.pmc. Some defaulted methods like this one have
useful defaults and don't throw exceptions.

=cut

*/


    VTABLE void init() {
        STRING * const meth     = CONST_STRING(interp, "init");
        PMC    * const classobj = Parrot_oo_get_class_str(interp, VTABLE_name(interp, SELF));
        PMC    * const sub      = Parrot_oo_find_vtable_override(interp, classobj, meth);

        if (!PMC_IS_NULL(sub))
            Parrot_run_meth_fromc(interp, sub, SELF, meth);
    }

    VTABLE void init_pmc(PMC *initializer) {
        STRING * const meth     = CONST_STRING(interp, "init_pmc");
        PMC    * const classobj = Parrot_oo_get_class_str(interp, VTABLE_name(interp, SELF));
        PMC    * const sub      = Parrot_oo_find_vtable_override(interp, classobj, meth);

        if (!PMC_IS_NULL(sub))
            Parrot_run_meth_fromc_args(interp, sub, pmc, meth,
                                       "vP", initializer);
    }

    VTABLE PMC *instantiate(PMC *sig) {
        STRING * const meth     = CONST_STRING(interp, "instantiate");
        PMC    * const classobj = Parrot_oo_get_class_str(interp, VTABLE_name(interp, SELF));
        PMC    * const sub      = Parrot_oo_find_vtable_override(interp, classobj, meth);

        if (PMC_IS_NULL(sub))
            return SUPER(sig);

        return (PMC *)Parrot_run_meth_fromc(INTERP, sub, SELF, meth);
    }

    VTABLE void destroy() {
        /* don't delegate destroy */
    }

    VTABLE void mark() {
        /* don't delegate mark */
    }

    VTABLE void add_method(STRING *method_name, PMC *sub_pmc) {
        SUPER(method_name, sub_pmc);
    }

    VTABLE STRING *name() {
        return SELF->vtable->whoami;
    }

    VTABLE PMC *get_namespace() {
        return SELF->vtable->_namespace;
    }

    VTABLE INTVAL type() {
        return SUPER();
    }

    VTABLE INTVAL isa(STRING *classname) {
        if (SUPER(classname))
            return 1;

        return 0;
    }

/*

=item C<opcode_t *invoke(void *next)>

Invokes a subroutine.

=cut

*/

    VTABLE opcode_t *invoke(void *next) {
        STRING * const meth     = CONST_STRING(interp, "invoke");
        PMC    * const classobj = Parrot_oo_get_class_str(interp, VTABLE_name(interp, SELF));
        PMC    * const sub      = Parrot_oo_find_vtable_override(interp, classobj, meth);

        if (PMC_IS_NULL(sub))
            vtable_meth_not_found(INTERP, SELF, "invoke");

        INTERP->current_object = SELF;
        return VTABLE_invoke(interp, sub, next);
    }

}

/*

=back

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
