/* perlundef.pmc
 *  Copyright: 2001-2003 The Perl Foundation.  All Rights Reserved.
 *  CVS Info
 *     $Id: perlundef.pmc,v 1.30 2003/08/25 09:46:23 leo Exp $
 *  Overview:
 *     These are the vtable functions for the perlundef base class
 *  Data Structure and Algorithms:
 *  History:
 *  Notes:
 *  References:
 */

#include "parrot/parrot.h"
#include "parrot/perltypes.h"

pmclass PerlUndef extends PerlInt {

    INTVAL get_integer () {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in integer context");
        return 0;
    }

    FLOATVAL get_number () {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in numeric context");
        return 0.0;
    }

    BIGNUM* get_bignum () {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in numeric context");
        return NULL; /* XXX - this should be zero in BIGNUM-ese */
    }

    STRING* get_string () {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in string context");
        return string_make(interpreter,  NULL, 0, NULL, 0, NULL);
    }

    PMC* get_pmc() {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in PMC context");
        return SELF;
    }

    INTVAL get_bool () {
        /* no warning: my $a; print $a if $a */
        return 0;
    }

    INTVAL is_same (PMC* pmc2) {
        return (INTVAL)(pmc2->vtable == pmc->vtable);
    }

    void set_integer (PMC * value) {
	DYNSELF.morph(enum_class_PerlInt);
        DYNSELF.set_integer(value);
    }

    void set_integer_native (INTVAL value) {
	DYNSELF.morph(enum_class_PerlInt);
        DYNSELF.set_integer_native(value);
    }

    void set_integer_same (PMC* value) {
        /* Do nothing; Can't happen? */
    }



    void set_string (PMC* value) {
	DYNSELF.morph(enum_class_PerlString);
        DYNSELF.set_string(value);
    }

    void set_string_native (STRING* value) {
	DYNSELF.morph(enum_class_PerlString);
        DYNSELF.set_string_native(value);
    }

    void add (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in addition");
	SUPER(value, dest);
    }

    void add_int (INTVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in integer addition");
        VTABLE_set_integer_native(INTERP, dest, value);
    }

    void add_bignum (BIGNUM* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in addition");
	SUPER(value, dest);
    }

    void add_float (FLOATVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in numeric addition");
        VTABLE_set_number_native(INTERP, dest, value);
    }

    void add_same (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in addition");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void subtract (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in subtraction");
	SUPER(value, dest);
    }

    void subtract_int (INTVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in integer subtraction");
        VTABLE_set_integer_native(INTERP, dest, 0-value);
    }

    void subtract_bignum (BIGNUM* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in subtraction");
	SUPER(value, dest);
    }

    void subtract_float (FLOATVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in numeric subtraction");
        VTABLE_set_number_native(INTERP, dest, 0-value);
    }

    void subtract_same (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in subtraction");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void multiply (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in multiplication");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void multiply_int (INTVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in integer multiplication");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void multiply_bignum (BIGNUM* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bignum multiplication");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void multiply_float (FLOATVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in numeric multiplication");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void multiply_same (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in multiplication");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void divide (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in division");
        if(value->vtable == &Parrot_base_vtables[enum_class_PerlUndef]) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }
        else if(value->vtable == &Parrot_base_vtables[enum_class_PerlInt]) {
            if(VTABLE_get_integer(INTERP, value) == 0) {
                internal_exception(DIV_BY_ZERO, "division by zero!\n");
            }
        }
        else if(VTABLE_get_number(INTERP, value) == 0) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }

        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void divide_int (INTVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in integer division");
        if(value == 0) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void divide_bignum (BIGNUM* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bignum division");
        /* need test for value == 0 */
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void divide_float (FLOATVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in numeric division");
        if(value == 0) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void divide_same (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in division");
        internal_exception(DIV_BY_ZERO, "division by zero!\n");
    }

    void modulus (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in modulus");
        if(value->vtable == &Parrot_base_vtables[enum_class_PerlUndef]) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }
        else if(value->vtable == &Parrot_base_vtables[enum_class_PerlInt]) {
            if(VTABLE_get_integer(INTERP, value) == 0) {
                internal_exception(DIV_BY_ZERO, "division by zero!\n");
            }
        }
        else if(VTABLE_get_number(INTERP, value) == 0) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }

        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void modulus_int (INTVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in integer modulus");
        if(value == 0) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void modulus_bignum (BIGNUM* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bignum modulus");
        /* need test for value == 0 */
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void modulus_float (FLOATVAL value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in numeric modulus");
        if(value == 0) {
            internal_exception(DIV_BY_ZERO, "division by zero!\n");
        }
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void modulus_same (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in modulus");
        internal_exception(DIV_BY_ZERO, "division by zero!\n");
    }

    void bitwise_or (PMC* value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bitwise or");
        VTABLE_set_integer(INTERP, dest, value);
    }

    void bitwise_or_int (INTVAL value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bitwise or");
        VTABLE_set_integer_native(INTERP, dest, value);
    }

    void bitwise_or_same (PMC* value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in bitwise or");
        VTABLE_set_integer(INTERP, dest, value);
    }

    void bitwise_and (PMC* value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bitwise and");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void bitwise_and_int (INTVAL value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bitwise and");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void bitwise_and_same (PMC* value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in bitwise and");
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void bitwise_xor (PMC* value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bitwise xor");
        VTABLE_set_integer(INTERP, dest, value);
    }

    void bitwise_xor_int (INTVAL value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bitwise xor");
        VTABLE_set_integer_native(INTERP, dest, value);
    }

    void bitwise_xor_same (PMC* value, PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of two uninitialized values in bitwise xor");
        VTABLE_set_integer(INTERP, dest, value);
    }

    void bitwise_not (PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in bitwise not");
        VTABLE_set_integer_native(INTERP, dest, ~((INTVAL)0));
    }

    void concatenate (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in concatenation");
        VTABLE_set_string(INTERP, dest, value);
    }

    void concatenate_native (STRING* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in concatenation");
        VTABLE_set_string_native(INTERP, dest, value);
    }

    void concatenate_same (PMC * value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in concatenation");
        VTABLE_set_string_native(INTERP, dest, NULL);
    }

    INTVAL is_equal (PMC* value) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in equals");
        if(value->vtable==SELF->vtable) {
            return 1;
        }
        else if(VTABLE_get_integer(INTERP, value) == 0) {
            return 1;
        }
        else if(0==string_compare(INTERP,
	    VTABLE_get_string(INTERP, value), NULL)) {
            return 1;
        }
        else {
            return 0;
        }
    }

    void logical_or (PMC* value,  PMC* dest) {
        VTABLE_set_integer_native(INTERP, dest,
	    VTABLE_get_bool(INTERP, value));
    }

    void logical_and (PMC* value,  PMC* dest) {
        VTABLE_set_integer_native(INTERP, dest, 0);
    }

    void logical_not (PMC* dest) {
        VTABLE_set_integer_native(INTERP, dest, 1);
    }

    void repeat (PMC* value,  PMC* dest) {
        Parrot_warn(INTERP, PARROT_WARNINGS_UNDEF_FLAG,
	    "Use of uninitialized value in repeat");
        VTABLE_set_string(INTERP, dest, NULL);
    }

    INTVAL defined () {
	return 0;
    }
    void increment () {
	DYNSELF.morph(enum_class_PerlInt);
        SELF->cache.int_val = 1;
    }


    void decrement () {
	DYNSELF.morph(enum_class_PerlInt);
        SELF->cache.int_val = -1;
    }


}
