/*
Copyright (C) 2004-2009, Parrot Foundation.
$Id: undef.pmc 46300 2010-05-05 03:58:50Z jimmy $

=head1 NAME

src/pmc/undef.pmc - Generic undefined value

=head1 DESCRIPTION

This is Parrot's generic undef type. This PMC has no defined value.
It returns a numeric value of 0, a boolean of false, and an empty string.
When assigned a number, integer, or string it morphs to a Number,
Integer, or String PMC respectively, and when assigned a generic PMC
it morphs into a PMC of the passed-in type and does a same-type assignment
from there.

=head2 Methods

=over 4

=cut

*/

#include "pmc/pmc_object.h"
#define UNDEF_STRING_CLASS enum_class_String

/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */

pmclass Undef no_ro {

/*

=item C<void set_pmc(PMC *other)>

Sets the current PMC to C<*other> by first changing the current PMC to the
appropriate type.

=cut

*/

    VTABLE void set_pmc(PMC *other) {
        if (!PObj_is_object_TEST(other)) {
            Parrot_pmc_reuse(INTERP, SELF, other->vtable->base_type, 0);
            VTABLE_set_pmc(INTERP, SELF, other);
        }
        else {
            PMC * const class_  = PARROT_OBJECT(other)->_class;
            PMC        *clone   = VTABLE_clone(INTERP, other);
            void       *attrs   = PMC_data(clone);
            PMC        *meta    = PMC_metadata(clone);

            /* now swap memory without leaking it */
            PMC_data(clone)     = PMC_data(SELF);
            PMC_data(SELF)      = attrs;
            SELF->vtable        = clone->vtable;

            /* Restore metadata. */
            if (!PMC_IS_NULL(meta)) {
                PMC * const iter = VTABLE_get_iter(INTERP, meta);
                while (VTABLE_get_bool(INTERP, iter)) {
                    STRING * const key = VTABLE_shift_string(INTERP, iter);
                    PMC * const value  = VTABLE_get_pmc_keyed_str(INTERP, meta, key);
                    VTABLE_setprop(INTERP, SELF, key, value);
                }
            }
            PMC_data(clone) = NULL;

            PObj_is_object_SET(SELF);
        }
    }

/*

=item C<void assign_pmc(PMC *other)>

Assigns the PMC to the value of C<*other> by first changing the PMC to the
appropriate type.

=cut

*/

    VTABLE void assign_pmc(PMC *other) {
        /* don't want to call set_pmc if we're assigning an Undef to an Undef */
        if (other->vtable->base_type != enum_class_Undef)
            VTABLE_set_pmc(INTERP, SELF, other);
    }


/*

=item C<INTVAL get_integer()>

Returns 0.

=cut

*/

    VTABLE INTVAL get_integer() {
        return 0;
    }

/*

=item C<INTVAL defined()>

Returns 0.

=cut

*/

    VTABLE INTVAL defined() {
        return 0;
    }

/*

=item C<void set_integer_native(INTVAL value)>

Morphs the current PMC to an C<Integer> and sets the value from C<value>.

=cut

*/

    VTABLE void set_integer_native(INTVAL value) {
        Parrot_pmc_reuse(INTERP, SELF, enum_class_Integer, 0);
        VTABLE_set_integer_native(INTERP, SELF, value);
    }

/*

=item C<FLOATVAL get_number()>

Returns 0.0.

=cut

*/

    VTABLE FLOATVAL get_number() {
        return 0.0;
    }

/*

=item C<void set_number_native(FLOATVAL value)>

Morphs the current PMC to a C<Float> and sets the value from C<value>.

=cut

*/

    VTABLE void set_number_native(FLOATVAL value) {
        Parrot_pmc_reuse(INTERP, SELF, enum_class_Float, 0);
        VTABLE_set_number_native(INTERP, SELF, value);
    }

/*

=item C<STRING *get_string()>

Returns an empty string.

=cut

*/

    VTABLE STRING *get_string() {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
            "Stringifying an Undef PMC");

        return Parrot_str_new_noinit(INTERP, enum_stringrep_one, 0);
    }

/*

=item C<void set_string_native(STRING *value)>

Morphs the current PMC to a C<String> and sets the value from C<value>.

=cut

*/

    VTABLE void set_string_native(STRING *value) {
        Parrot_pmc_reuse(INTERP, SELF, enum_class_String, 0);
        VTABLE_set_string_native(INTERP, SELF, value);
    }

/*

=item C<INTVAL get_bool()>

Returns 0.

=cut

*/

    VTABLE INTVAL get_bool() {
        return 0;
    }

/*

=item C<INTVAL logical_not()>

Returns 1.

=cut

*/

    VTABLE PMC *logical_not(PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
        VTABLE_set_bool(INTERP, dest, 1);
        return dest;
    }

/*

=item C<void share()>

Unknown. (TODO)

=cut

*/

    VTABLE void share() {
        /* see src/pmc/integer.pmc */
    }

/*

=item C<PMC *share_ro()>

Unknown. (TODO)

=cut

*/

    VTABLE PMC *share_ro() {
        if (PObj_is_PMC_shared_TEST(SELF))
            return SELF;
        else
            return pt_shared_fixup(INTERP, SELF);
    }

/*

=item C<PMC *clone()>

Clones the current Undef PMC.

=cut

*/

    VTABLE PMC *clone() {
        return Parrot_pmc_new(INTERP, SELF->vtable->base_type);
    }

/*

=item C<INTVAL is_equal(PMC *value)>

Returns 1 if the C<*value> is an Undef PMC, 0 otherwise.

=cut

*/

    MULTI INTVAL is_equal(Undef value) {
        return 1;
    }

    MULTI INTVAL is_equal(DEFAULT value) {
        return 0;
    }
}

/*

=back

=cut

*/


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