/*
$Id: /mirror/trunk/languages/perl6/src/pmc/mutablevar.pmc 30945 2008-09-08T20:50:52.283286Z julianalbo  $
Copyright (C) 2001-2008, The Perl Foundation.

=head1 NAME

src/pmc/mutablevar.pmc - PMC implementing VAR functionality

=head1 DESCRIPTION

The MutableVAR PMC provides access to the container type of a scalar. This is
needed as scalar containers forward to their contents.

=head2 Methods

=cut

*/

#include "parrot/parrot.h"

pmclass MutableVAR need_ext dynpmc group perl6_group {
    ATTR PMC *scalar;

    VTABLE void init() {
        Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
            "Must initialize MutableVAR with a scalar");
    }

    VTABLE void init_pmc(PMC *scalar) {
        /* Need custom mark and destroy. */
        PObj_custom_mark_SET(SELF);
        PObj_active_destroy_SET(SELF);

        /* Create underlying structure and set scalar value. */
        PMC_data(SELF) = mem_allocate_zeroed_typed(Parrot_MutableVAR_attributes);
        SET_ATTR_scalar(INTERP, SELF, scalar);
    }

    VTABLE void mark() {
        PMC *scalar;
        GET_ATTR_scalar(INTERP, SELF, scalar);
        if (scalar)
            pobject_lives(INTERP, (PObj*)scalar);
    }

    VTABLE void destroy() {
        mem_sys_free(PMC_data(SELF));
        PMC_data(SELF) = NULL;
    }

    VTABLE PMC *find_method(STRING *method_name) {
        PMC *scalar;
        PMC *mro;
        INTVAL elements, i;
        GET_ATTR_scalar(INTERP, SELF, scalar);

        /* We can't get Parrot do dispatch this for us as usual, because it
         * calls VTABLE_namespace, which delegates to what the mutable
         * contains. We want to call on the container. */
        mro = scalar->vtable->mro;
        elements = VTABLE_elements(INTERP, mro);
        for (i = 0; i < elements; i++) {
            PMC *cur_class = VTABLE_get_pmc_keyed_int(INTERP, mro, i);
            PMC *ns = cur_class->vtable->_namespace;
            if (!PMC_IS_NULL(ns)) {
                PMC *method = VTABLE_get_pmc_keyed_str(interp, ns, method_name);
                if (!PMC_IS_NULL(method)) {
                    /* Found method. If it's an NCI, we return a BoundNCI, to
                     * make sure we call with the scalar invocant. */
                    return method;
                }
            }
        }
        return PMCNULL;
    }

    VTABLE PMC* getprop(STRING *prop_name) {
        PMC *scalar;
        GET_ATTR_scalar(INTERP, SELF, scalar);
        return VTABLE_getprop(INTERP, scalar, prop_name);
    }
}


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

