/*
Copyright (C) 2001-2006, The Perl Foundation.
$Id: scalar.pmc 16275 2006-12-28 01:20:44Z particle $

=head1 NAME

src/pmc/scalar.pmc - Scalar Abstract Superclass

=head1 DESCRIPTION

These are the vtable functions for the scalar base PMC class

=head2 Methods

=over 4

=cut

*/

#include "parrot/parrot.h"

pmclass scalar abstract noinit {

/*

=item C<void morph(INTVAL type)>

Morphs the scalar to the specified type.

=cut

*/

    void morph(INTVAL type) {
        if (SELF->vtable->base_type == type)
            return;
        pmc_reuse(INTERP, SELF, type, 0);
    }
/*

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

Sets the PMC C<*value>, calling the appropriate C<set_*> method
according to the type of C<*value>.

=cut

*/

    void assign_pmc(PMC* value) {
        STRING *s_int = CONST_STRING(INTERP, "Integer");
        STRING *s_num = CONST_STRING(INTERP, "Float");
        STRING *s_str = CONST_STRING(INTERP, "String");
        if (SELF->vtable->base_type == enum_class_Boolean) {
            /* doesn't morph */
            DYNSELF.morph(value->vtable->base_type);
        }
        if (value->vtable->base_type == enum_class_Undef ||
                value->vtable->base_type == enum_class_Undef) {
            DYNSELF.morph(value->vtable->base_type);
            return;
        }
        if (VTABLE_isa(INTERP, value, s_int)) {
            INTVAL v = VTABLE_get_integer(INTERP, value);
            DYNSELF.set_integer_native(v);
            return;
        }
        if (VTABLE_isa(INTERP, value, s_num)) {
            FLOATVAL v = VTABLE_get_number(INTERP, value);
            DYNSELF.set_number_native(v);
            return;
        }
        if (VTABLE_isa(INTERP, value, s_str)) {
            STRING* v = VTABLE_get_string(INTERP, value);
            DYNSELF.set_string_native(v);
            return;
        }
        DYNSELF.morph(enum_class_Ref);
        DYNSELF.set_pmc(value);
    }

/*

=item C<PMC *clone()>

Creates and returns a clone of the scalar.

=cut

*/

    PMC* clone() {
        PMC* dest = pmc_new(INTERP, SELF->vtable->base_type);
        memcpy(&PMC_union(dest), &PMC_union(SELF), sizeof (UnionVal));
        return dest;
    }


/*

=back

=head1 Mathematical Methods

=over 4

=item C<PMC* subtract(PMC *value, PMC *dest)>

=cut

*/

/*

=item C<void add(PMC *value, PMC *dest)>

=item C<void add_int(INTVAL value, PMC *dest)>

=item C<void add_float(FLOATVAL value, PMC *dest)>

Adds C<value> to the number and returns the result in C<*dest>.
If C<dest> is NULL it's created.

=item C<void i_add(PMC *value)>

=item C<void i_add(INTVAL value)>

=item C<void i_add(FLOATVAL value)>

Adds C<value> to C<SELF> inplace.

=cut

*/

    PMC* add(PMC* value, PMC* dest) {
MMD_Complex: {
            FLOATVAL a = DYNSELF.get_number();
            if (dest)
                VTABLE_morph(INTERP, dest, value->vtable->base_type);
            else
                dest = pmc_new(INTERP, value->vtable->base_type);
            VTABLE_set_number_native(INTERP, dest,
                    a + VTABLE_get_number_keyed_int(INTERP, value, 0));
            VTABLE_set_number_keyed_int(INTERP, dest, 1,
                    VTABLE_get_number_keyed_int(INTERP, value, 1));
            return dest;
        }
MMD_DEFAULT: {
            if (!dest)
                dest = pmc_new(INTERP, SELF->vtable->base_type);
            VTABLE_set_number_native(INTERP, dest,
                    DYNSELF.get_number() + VTABLE_get_number(INTERP, value));
            return dest;
        }
    }

    PMC* add_int(INTVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                DYNSELF.get_number() + (FLOATVAL)value);
        return dest;
    }

    PMC* add_float(FLOATVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                DYNSELF.get_number() + value);
        return dest;
    }

    void i_add(PMC* value) {
MMD_Complex: {
            FLOATVAL a = DYNSELF.get_number();
            VTABLE_morph(INTERP, SELF, value->vtable->base_type);
            VTABLE_set_number_native(INTERP, SELF,
                    a + VTABLE_get_number_keyed_int(INTERP, value, 0));
            VTABLE_set_number_keyed_int(INTERP, SELF, 1,
                    VTABLE_get_number_keyed_int(INTERP, value, 1));
        }
MMD_DEFAULT: {
            VTABLE_set_number_native(INTERP, SELF,
                DYNSELF.get_number() + VTABLE_get_number(INTERP, value));
        }
    }

    void i_add_int(INTVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            DYNSELF.get_number() + (FLOATVAL)value);
    }

    void i_add_float(FLOATVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            DYNSELF.get_number() + value);
    }

/*

=item C<PMC* subtract(PMC *value, PMC *dest)>

=item C<PMC* subtract_int(INTVAL value, PMC *dest)>

=item C<PMC* subtract_float(FLOATVAL value, PMC *dest)>

Subtracts C<value> from the number and returns the result in C<*dest>.
If C<dest> doesn't exist a new C<Float> is created.

=item C<void i_subtract(PMC *value)>

=item C<void i_subtract_int(INTVAL value)>

=item C<void i_subtract_float(FLOATVAL value)>

Subtracts C<value> from C<SELF> inplace.

=cut

*/

    PMC* subtract(PMC* value, PMC* dest) {
MMD_Complex: {
            FLOATVAL a = DYNSELF.get_number();
            if (dest)
                VTABLE_morph(INTERP, dest, value->vtable->base_type);
            else
                dest = pmc_new(INTERP, value->vtable->base_type);
            VTABLE_set_number_native(INTERP, dest,
                    a - VTABLE_get_number_keyed_int(INTERP, value, 0));
            VTABLE_set_number_keyed_int(INTERP, dest, 1,
                    -VTABLE_get_number_keyed_int(INTERP, value, 1));
            return dest;
        }
MMD_DEFAULT: {
            if (!dest)
                dest = pmc_new(INTERP, SELF->vtable->base_type);
            VTABLE_set_number_native(INTERP, dest,
                    DYNSELF.get_number() - VTABLE_get_number(INTERP, value));
            return dest;
        }
    }

    PMC* subtract_int(INTVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                DYNSELF.get_number() - (FLOATVAL)value);
        return dest;
    }

    PMC* subtract_float(FLOATVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                DYNSELF.get_number() - value);
        return dest;
    }

    void i_subtract(PMC* value) {
MMD_Complex: {
            FLOATVAL a = DYNSELF.get_number();
            VTABLE_morph(INTERP, SELF, value->vtable->base_type);
            VTABLE_set_number_native(INTERP, SELF,
                    a - VTABLE_get_number_keyed_int(INTERP, value, 0));
            VTABLE_set_number_keyed_int(INTERP, SELF, 1,
                    -VTABLE_get_number_keyed_int(INTERP, value, 1));
        }
MMD_DEFAULT: {
            VTABLE_set_number_native(INTERP, SELF,
                DYNSELF.get_number() - VTABLE_get_number(INTERP, value));
        }
    }

    void i_subtract_int(INTVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            DYNSELF.get_number() - (FLOATVAL)value);
    }

    void i_subtract_float(FLOATVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            DYNSELF.get_number() - value);
    }


/*

=item C<PMC* multiply(PMC *value, PMC *dest)>

=item C<PMC* multiply_int(INTVAL value, PMC *dest)>

=item C<PMC* multiply_float(FLOATVAL value, PMC *dest)>

Multiplies the number by C<value> and returns the result in C<*dest>.

=cut

*/

    PMC* multiply(PMC* value, PMC* dest) {
MMD_Complex: {
            real_exception(INTERP, NULL, E_NotImplementedError,
                    "TODO mul<Float, Complex>");
            return dest;
        }
MMD_DEFAULT: {
            if (!dest)
                dest = pmc_new(INTERP, SELF->vtable->base_type);
            VTABLE_set_number_native(INTERP, dest,
                DYNSELF.get_number() * VTABLE_get_number(INTERP, value));
            return dest;
        }
    }

    PMC* multiply_int(INTVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
            DYNSELF.get_number() * value);
        return dest;
    }

    PMC* multiply_float(FLOATVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
            DYNSELF.get_number() * value);
        return dest;
    }

    void i_multiply(PMC* value) {
MMD_Complex: {
            real_exception(INTERP, NULL, E_NotImplementedError,
                    "TODO i_mul<Float, Complex>");
        }
MMD_DEFAULT: {
            VTABLE_set_number_native(INTERP, SELF,
                DYNSELF.get_number() * VTABLE_get_number(INTERP, value));
        }
    }

    void i_multiply_int(INTVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            DYNSELF.get_number() * (FLOATVAL)value);
    }

    void i_multiply_float(FLOATVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            DYNSELF.get_number() * value);
    }

/*

=item C<PMC* divide(PMC *value, PMC *dest)>

=item C<PMC* divide_int(INTVAL value, PMC *dest)>

=item C<PMC* divide_float(FLOATVAL value, PMC *dest)>

Divides the number by C<value> and returns the result in C<*dest>.

=item C<void i_divide(PMC *value)>

=item C<void i_divide_int(INTVAL value)>

=item C<void i_divide_float(FLOATVAL value)>

Divides C<SELF> by C<value> inplace.

=cut

*/

    PMC* divide(PMC* value, PMC* dest) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest, DYNSELF.get_number() / d);
        return dest;
    }

    PMC* divide_int(INTVAL value, PMC* dest) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest, DYNSELF.get_number() / value);
        return dest;
    }

    PMC* divide_float(FLOATVAL value, PMC* dest) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest, DYNSELF.get_number() / value);
        return dest;
    }

    void i_divide(PMC* value) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        VTABLE_set_number_native(INTERP, SELF, DYNSELF.get_number() / d);
    }

    void i_divide_int(INTVAL value) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        VTABLE_set_number_native(INTERP, SELF, DYNSELF.get_number() / value);
    }

    void i_divide_float(FLOATVAL value) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        VTABLE_set_number_native(INTERP, SELF, DYNSELF.get_number() / value);
    }

/*

=item C<PMC* floor_divide(PMC *value, PMC *dest)>

=item C<PMC* floor_divide_int(INTVAL value, PMC *dest)>

=item C<PMC* floor_divide_float(FLOATVAL value, PMC *dest)>

Divides the number by C<value> and returns the result in C<*dest>.

=item C<void i_floor_divide(PMC *value)>

=item C<void i_floor_divide_int(INTVAL value)>

=item C<void i_floor_divide_float(FLOATVAL value)>

Divides C<SELF> by C<value> inplace.

=cut

*/

    PMC* floor_divide(PMC* value, PMC* dest) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                floor(DYNSELF.get_number() / d));
        return dest;
    }

    PMC* floor_divide_int(INTVAL value, PMC* dest) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                floor(DYNSELF.get_number() / value));
        return dest;
    }

    PMC* floor_divide_float(FLOATVAL value, PMC* dest) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                floor(DYNSELF.get_number() / value));
        return dest;
    }

    void i_floor_divide(PMC* value) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        VTABLE_set_number_native(INTERP, SELF,
                floor(DYNSELF.get_number() / d));
    }

    void i_floor_divide_int(INTVAL value) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        VTABLE_set_number_native(INTERP, SELF,
                floor(DYNSELF.get_number() / value));
    }

    void i_floor_divide_float(FLOATVAL value) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float division by zero");
        VTABLE_set_number_native(INTERP, SELF,
                floor(DYNSELF.get_number() / value));
    }


/*

=item C<PMC* cmodulus(PMC *value, PMC *dest)>

=item C<PMC* cmodulus(INTVAL value, PMC *dest)>

=item C<PMC* cmodulus(FLOATVAL value, PMC *dest)>

Calculates the value of the number C-style C<mod> C<value> and returns
the result in C<dest>.

=item C<void i_cmodulus(PMC *value)>

=item C<void i_cmodulus(INTVAL value)>

=item C<void i_cmodulus(FLOATVAL value)>

Calculates the value of the number C-style C<mod> C<value> and returns
the result in C<dest>.

=cut

*/

    PMC* cmodulus(PMC* value, PMC* dest) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float cmodulus by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                fmod(DYNSELF.get_number(), d));
        return dest;
    }

    PMC* cmodulus_float(FLOATVAL value, PMC* dest) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float cmodulus by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                fmod(DYNSELF.get_number(), value));
        return dest;
    }

    PMC* cmodulus_float(FLOATVAL value, PMC* dest) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float cmodulus by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                fmod(DYNSELF.get_number(), value));
        return dest;
    }
    void i_cmodulus(PMC* value) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float cmodulus by zero");
        VTABLE_set_number_native(INTERP, SELF,
                fmod(DYNSELF.get_number() , d));
    }

    void i_cmodulus_int(INTVAL value) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float cmodulus by zero");
        VTABLE_set_number_native(INTERP, SELF,
                fmod(DYNSELF.get_number() , value));
    }

    void i_cmodulus_float(FLOATVAL value) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float cmodulus by zero");
        VTABLE_set_number_native(INTERP, SELF,
                fmod(DYNSELF.get_number() , value));
    }

/*

=item C<PMC* modulus(PMC *value, PMC *dest)>

=item C<PMC* modulus(INTVAL value, PMC *dest)>

=item C<PMC* modulus(FLOATVAL value, PMC *dest)>

Calculates the value of corrected C<mod> C<value> and returns
the result in C<dest>. See also ops/math.ops.

=item C<void i_modulus(PMC *value)>

=item C<void i_modulus(INTVAL value)>

=item C<void i_modulus(FLOATVAL value)>

Calculates modulus inplace

=cut

*/

    PMC* modulus(PMC* value, PMC* dest) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float modulus by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                floatval_mod(DYNSELF.get_number(), d));
        return dest;
    }

    PMC* modulus_int(INTVAL value, PMC* dest) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float modulus by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                floatval_mod(DYNSELF.get_number(), value));
        return dest;
    }

    PMC* modulus_float(FLOATVAL value, PMC* dest) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float modulus by zero");
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                floatval_mod(DYNSELF.get_number(), value));
        return dest;
    }

    void i_modulus(PMC* value) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (d == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float modulus by zero");
        VTABLE_set_number_native(INTERP, SELF,
                floatval_mod(DYNSELF.get_number() , d));
    }

    void i_modulus_int(INTVAL value) {
        if (value == 0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float modulus by zero");
        VTABLE_set_number_native(INTERP, SELF,
                floatval_mod(DYNSELF.get_number() , value));
    }

    void i_modulus_float(FLOATVAL value) {
        if (value == 0.0)
            real_exception(INTERP, NULL, E_ZeroDivisionError,
                    "float modulus by zero");
        VTABLE_set_number_native(INTERP, SELF,
                floatval_mod(DYNSELF.get_number() , value));
    }

/*

=item C<PMC* pow(PMC *value, PMC *dest)>

=item C<PMC* pow_int(INTVAL value, PMC *dest)>

=item C<PMC* pow_float(FLOATVAL value, PMC *dest)>

Calculates  C<SELF pow value> and returns
the result in C<dest>. See also ops/math.ops.

=item C<void i_pow(PMC *value)>

=item C<void i_pow_int(INTVAL value)>

=item C<void i_pow_float(FLOATVAL value)>

Calculates pow inplace

=cut

*/

    PMC* pow(PMC* value, PMC* dest) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                pow(DYNSELF.get_number(), d));
        return dest;
    }

    PMC* pow_int(INTVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                pow(DYNSELF.get_number(), value));
        return dest;
    }

    PMC* pow_float(FLOATVAL value, PMC* dest) {
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_number_native(INTERP, dest,
                pow(DYNSELF.get_number(), value));
        return dest;
    }

    void i_pow(PMC* value) {
        FLOATVAL d = VTABLE_get_number(INTERP, value);

        VTABLE_set_number_native(INTERP, SELF,
                pow(DYNSELF.get_number(), d));
    }

    void i_pow_int(INTVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
                pow(DYNSELF.get_number(), value));
    }

    void i_pow_float(FLOATVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
                pow(DYNSELF.get_number(), value));
    }

/*

=item C<PMC* neg(PMC *dest)>

=item C<void i_neg()>

Set C<dest> to the negated value of C<SELF>.

=cut

*/

    PMC* neg(PMC* dest) {
        INTVAL a = -DYNSELF.get_integer();
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, a);
        return dest;
    }

    void i_neg() {
        VTABLE_set_integer_native(INTERP, SELF, -DYNSELF.get_integer());
    }

/*

=back

=head2 Bitwise Methods

=over 4

=item C<PMC* bitwise_or(PMC *value, PMC *dest)>

=item C<PMC* bitwise_or_int(INTVAL value, PMC *dest)>

Returns in C<*dest> the bitwise C<OR> of the scalar and C<value>.

=item C<void i_bitwise_or(PMC *value)>

=item C<void i_bitwise_or_int(INTVAL value)>

Inplace bitwise or.

=cut

*/

    PMC* bitwise_or(PMC* value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() | VTABLE_get_integer(INTERP, value);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }


    PMC* bitwise_or_int(INTVAL value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() | value;
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    void i_bitwise_or(PMC* value) {
        INTVAL result;

        result = DYNSELF.get_integer() | VTABLE_get_integer(INTERP, value);
        DYNSELF.set_integer_native(result);
    }


    void i_bitwise_or_int(INTVAL value) {
        INTVAL result;

        result = DYNSELF.get_integer() | value;
        DYNSELF.set_integer_native(result);
    }

/*

=item C<PMC* bitwise_and(PMC *value, PMC *dest)>

=item C<PMC* bitwise_and_int(INTVAL value, PMC *dest)>

Returns in C<*dest> the bitwise C<AND> of the scalar and C<value>.

=item C<void i_bitwise_and(PMC *value)>

=item C<void i_bitwise_and_int(INTVAL value)>

Inplace bitwise and.

=cut

*/

    PMC* bitwise_and(PMC* value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() & VTABLE_get_integer(INTERP, value);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    PMC* bitwise_and_int(INTVAL value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() & value;
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    void i_bitwise_and(PMC* value) {
        INTVAL result;

        result = DYNSELF.get_integer() & VTABLE_get_integer(INTERP, value);
        DYNSELF.set_integer_native(result);
    }


    void i_bitwise_and_int(INTVAL value) {
        INTVAL result;

        result = DYNSELF.get_integer() & value;
        DYNSELF.set_integer_native(result);
    }

/*

=item C<void bitwise_xor(PMC *value, PMC *dest)>

=item C<void bitwise_xor_int(INTVAL value, PMC *dest)>

Returns in C<*dest> the bitwise C<XOR> of the scalar and C<*value>.

=item C<void i_bitwise_xor(PMC *value)>

=item C<void i_bitwise_xor_int(INTVAL value)>

Inplace bitwise and.

=cut

*/

    PMC* bitwise_xor(PMC* value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() ^ VTABLE_get_integer(INTERP, value);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    PMC* bitwise_xor_int(INTVAL value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() ^ value;
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    void i_bitwise_xor(PMC* value) {
        INTVAL result;

        result = DYNSELF.get_integer() ^ VTABLE_get_integer(INTERP, value);
        DYNSELF.set_integer_native(result);
    }

    void i_bitwise_xor_int(INTVAL value) {
        INTVAL result;

        result = DYNSELF.get_integer() ^ value;
        DYNSELF.set_integer_native(result);
    }

/*

=item C<PMC* bitwise_not(PMC *dest)>

=item C<void i_bitwise_not()>

Returns in C<*dest> the bitwise negation of the scalar and C<value>.

=cut

*/

    PMC* bitwise_not(PMC* dest) {
        INTVAL a = ~DYNSELF.get_integer();
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, a);
        return dest;
    }

    void i_bitwise_not() {
        VTABLE_set_integer_native(INTERP, SELF, ~DYNSELF.get_integer());
    }


/*

=item C<PMC* bitwise_shr(PMC *value, PMC *dest)>

=item C<PMC* bitwise_shr_int(INTVAL value, PMC *dest)>

Returns in C<*dest> the arithmetic shift right of the scalar by C<value>.

=item C<void i_bitwise_shr(PMC *value)>

=item C<void i_bitwise_shr_int(INTVAL value)>

Inplace shift right.

=cut

*/

    PMC* bitwise_shr(PMC* value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() >> VTABLE_get_integer(INTERP, value);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    PMC* bitwise_shr_int(INTVAL value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() >> value;
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    void i_bitwise_shr(PMC* value) {
        INTVAL result;

        result = DYNSELF.get_integer() >> VTABLE_get_integer(INTERP, value);
        DYNSELF.set_integer_native(result);
    }

    void i_bitwise_shr_int(INTVAL value) {
        INTVAL result;

        result = DYNSELF.get_integer() >> value;
        DYNSELF.set_integer_native(result);
    }

/*

=item C<PMC* bitwise_lsr(PMC *value, PMC *dest)>

=item C<PMC* bitwise_lsr_int(INTVAL value, PMC *dest)>

Returns in C<*dest> the logical shift right of the scalar by C<*value>.

=item C<void i_bitwise_lsr(PMC *value)>

=item C<void i_bitwise_lsr_int(INTVAL value)>

Inplace shift right.

=cut

*/

    PMC* bitwise_lsr(PMC* value, PMC* dest) {
        INTVAL result;

        result = (UINTVAL)DYNSELF.get_integer() >>
            VTABLE_get_integer(INTERP, value);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    PMC* bitwise_lsr_int(INTVAL value, PMC* dest) {
        INTVAL result;

        result = (UINTVAL)DYNSELF.get_integer() >> value;
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    void i_bitwise_lsr(PMC* value) {
        INTVAL result;

        result = (UINTVAL)DYNSELF.get_integer() >>
                VTABLE_get_integer(INTERP, value);
        DYNSELF.set_integer_native(result);
    }

    void i_bitwise_lsr_int(INTVAL value) {
        INTVAL result;

        result = (UINTVAL)DYNSELF.get_integer() >> value;
        DYNSELF.set_integer_native(result);
    }

/*

=item C<PMC* bitwise_shl(PMC *value, PMC *dest)>

=item C<PMC* bitwise_shl_int(INTVAL value, PMC *dest)>

Returns in C<*dest> the shift left of the scalar by C<*value>.

=item C<void i_bitwise_shl(PMC *value)>

=item C<void i_bitwise_shl_int(INTVAL value)>

Inplace shift left.

=cut

*/

    PMC* bitwise_shl(PMC* value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() << VTABLE_get_integer(INTERP, value);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    PMC* bitwise_shl_int(INTVAL value, PMC* dest) {
        INTVAL result;

        result = DYNSELF.get_integer() << value;
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_integer_native(INTERP, dest, result);
        return dest;
    }

    void i_bitwise_shl(PMC* value) {
        INTVAL result;

        result = DYNSELF.get_integer() << VTABLE_get_integer(INTERP, value);
        DYNSELF.set_integer_native(result);
    }

    void i_bitwise_shl_int(INTVAL value) {
        INTVAL result;

        result = DYNSELF.get_integer() << value;
        DYNSELF.set_integer_native(result);
    }

/*

=back

=head2 String Methods

=over 4

=item C<PMC* concatenate(PMC *value, PMC *dest)>

=item C<PMC* concatenate_str(STRING *value, PMC *dest)>

Returns in C<*dest> the result of concatenating the scalar and C<*value>.

=item C<void concatenate(PMC *value)>

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

Concatenate the string C<value> in place.

=cut

*/

    PMC* concatenate(PMC* value,  PMC* dest) {
        STRING* s = string_concat(INTERP,
            DYNSELF.get_string(),
            VTABLE_get_string(INTERP, value), 0);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_string_native(INTERP, dest, s);
        return dest;
    }

    PMC* concatenate_str(STRING* value,  PMC* dest) {
        STRING* s = string_concat(INTERP,
            DYNSELF.get_string(), value, 0);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_string_native(INTERP, dest, s);
        return dest;
    }

    void i_concatenate(PMC* value) {
        STRING* s = DYNSELF.get_string();
        STRING* v = VTABLE_get_string(INTERP, value);
        DYNSELF.set_string_native(string_append(INTERP, s, v));
    }

    void i_concatenate_str(STRING* value) {
        STRING* s = DYNSELF.get_string();
        DYNSELF.set_string_native( string_append(INTERP, s, value));
    }

/*

=item C<PMC* repeat(PMC *value, PMC *dest)>

=item C<PMC* repeat_int(INTVAL value, PMC *dest)>

Returns in C<*dest> the result of repeating the scalar C<value> times.

=item C<void i_repeat(PMC *value)>

=item C<void i_repeat_int(INTVAL value)>

Repeat the string C<SELF> in place C<value> times.

=cut

*/

    PMC* repeat(PMC* value,  PMC* dest) {
        STRING* s = DYNSELF.get_string();
        UINTVAL n = (UINTVAL)VTABLE_get_integer(INTERP, value);
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_string_native(INTERP, dest,
            string_repeat(INTERP, s, n, NULL));
        return dest;
    }

    PMC* repeat_int(INTVAL value, PMC* dest) {
        STRING* s = DYNSELF.get_string();
        UINTVAL n = value;
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_string_native(INTERP, dest,
            string_repeat(INTERP, s, n, NULL));
        return dest;
    }


    void i_repeat(PMC* value) {
        STRING* s = DYNSELF.get_string();
        UINTVAL n = (UINTVAL)VTABLE_get_integer(INTERP, value);
        DYNSELF.set_string_native(string_repeat(INTERP, s, n, NULL));
    }

    void i_repeat_int(INTVAL value) {
        STRING* s = DYNSELF.get_string();
        UINTVAL n = value;
        DYNSELF.set_string_native(string_repeat(INTERP, s, n, NULL));
    }



/*

=back

=head2 Compare Methods

=over 4

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

Returns the result of comparing the floating-point values of the scalar
and C<*value>.

=cut

*/

    INTVAL cmp_num(PMC* value) {
        /* XXX - Floating-point precision errors possible? */
        FLOATVAL diff = VTABLE_get_number(INTERP, value) -
                        DYNSELF.get_number();

        return diff == 0.0 ? 0 : diff < 0.0 ? -1 : 1;
    }

/*

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

Returns the result of comparing the string values of the scalar and
C<*value>.

=cut

*/

    INTVAL cmp_string(PMC* value) {
        return string_compare(INTERP, DYNSELF.get_string(),
            VTABLE_get_string(INTERP, value));
    }

/*

=back

=head2 Logical Methods

=over 4

=item C<PMC* logical_or(PMC *value, PMC *dest)>

Returns the result of the logical C<OR> of C<SELF> and C<value>, i.e. returns
C<SELF> it is true or C<value>: C<dest> is alway ignored.

=cut

*/

    PMC* logical_or(PMC* value,  PMC* dest) {
        if (DYNSELF.get_bool()) {
            return SELF;
        }
        return value;
    }

/*

=item C< PMC* logical_and(PMC *value, PMC *dest)>

Returns the result of the logical C<AND> of C<SELF> and C<value>, i.e.
returns C<value> if C<SELF> is true else C<SELF>. C<dest> is always ignored.

=cut

*/

    PMC* logical_and(PMC* value,  PMC* dest) {
        if (DYNSELF.get_bool()) {
            return value;
        }
        return SELF;
    }

/*

=item C<PMC* logical_xor(PMC *value, PMC *dest)>

Returns the result of the logical C<XOR> of C<SELF> and C<*value>.

=cut

*/

    PMC* logical_xor(PMC* value,  PMC* dest) {
        INTVAL my_bool, value_bool;

        my_bool = DYNSELF.get_bool();
        value_bool = VTABLE_get_bool(INTERP, value);

        if (my_bool && ! value_bool) {
            return SELF;
        }
        else if (value_bool && ! my_bool) {
            return value;
        }
        dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_bool(INTERP, dest, 0);
        return dest;
    }

/*

=item C<PMC* logical_not(PMC *dest)>

=item C<void i_logical_not()>

Returns in C<*dest> the result of the logical negation of the scalar and
C<*value>.

=cut

*/

    PMC* logical_not(PMC* dest) {
        INTVAL a = ! DYNSELF.get_bool();
        if (!dest)
            dest = pmc_new(INTERP, SELF->vtable->base_type);
        VTABLE_set_bool(INTERP, dest, a);
        return dest;
    }

    void i_logical_not() {
        VTABLE_set_bool(INTERP, SELF, ! DYNSELF.get_bool());
    }

/*

=item C<INTVAL defined()>

Always returns true.

=cut

*/

    INTVAL defined() {
        return 1;
    }


/*

=item C<STRING *substr_str(INTVAL offset, INTVAL length)>

Returns the substring of length C<length> of the scalar starting at
C<offset>.

=cut

*/

    STRING* substr_str(INTVAL offset, INTVAL length) {
        return string_substr(INTERP, VTABLE_get_string(INTERP,SELF),
            offset, length, NULL, 0);
    }

/*

=item C<void share_ro()>

Sets this PMC as shared and read-only.

=cut

*/
    PMC* share_ro() {
        PMC *true;
        PMC *ret;

        true = pmc_new(INTERP, enum_class_Integer);
        VTABLE_set_integer_native(INTERP, true, 1);

        ret = pt_shared_fixup(INTERP, SELF);

        /* first set readonly */
        VTABLE_setprop(INTERP, ret, const_string(INTERP, "_ro"), true);


        /* now share; we add a PMC_EXT so we can identify the owning interp */
        add_pmc_sync(INTERP, ret);
        PObj_is_PMC_shared_SET(ret);

        /* XXX FIXME workaround lack of metadata sharing*/
        PMC_metadata(SELF) = NULL;

        return ret;
    }

}

/*

=back

=cut

*/

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