/*
Copyright (C) 2001-2009, Parrot Foundation.
$Id: scalar.pmc 46289 2010-05-04 22:16:04Z bacek $

=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 "pmc/pmc_bigint.h"

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

pmclass scalar {

/*

=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

*/

    VTABLE void assign_pmc(PMC *value) {
        INTVAL  self_type = VTABLE_type(INTERP, SELF);
        INTVAL  val_type  = VTABLE_type(INTERP, value);

        if (self_type == enum_class_Boolean)
            /* doesn't morph */
            Parrot_pmc_reuse(INTERP, SELF, val_type, 0);

        if (val_type == enum_class_Undef) {
            Parrot_pmc_reuse(INTERP, SELF, val_type, 0);
            return;
        }

        if (VTABLE_isa(INTERP, value, CONST_STRING(INTERP, "Undef"))) {
            Parrot_pmc_reuse(INTERP, SELF, enum_class_Undef, 0);
            return;
        }

        if (VTABLE_isa(INTERP, value, CONST_STRING(INTERP, "Integer"))) {
            const INTVAL v = VTABLE_get_integer(INTERP, value);
            SELF.set_integer_native(v);
            return;
        }

        if (VTABLE_isa(INTERP, value, CONST_STRING(INTERP, "Float"))) {
            const FLOATVAL v = VTABLE_get_number(INTERP, value);
            SELF.set_number_native(v);
            return;
        }

        if (VTABLE_isa(INTERP, value, CONST_STRING(INTERP, "String"))) {
            STRING * const v = VTABLE_get_string(INTERP, value);
            SELF.set_string_native(v);
            return;
        }
        Parrot_pmc_reuse(INTERP, SELF, val_type, 0);
        SELF.set_pmc(value);
    }

/*

=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

*/

    MULTI PMC *add(Complex value, PMC *dest) {
        const FLOATVAL a = SELF.get_number();

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, value));

        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;
    }

    MULTI PMC *add(DEFAULT value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                SELF.get_number() + VTABLE_get_number(INTERP, value));
        return dest;
    }

    VTABLE PMC *add_int(INTVAL value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                SELF.get_number() + (FLOATVAL)value);
        return dest;
    }

    VTABLE PMC *add_float(FLOATVAL value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                SELF.get_number() + value);
        return dest;
    }

    MULTI void i_add(Complex value) {
        const FLOATVAL a = SELF.get_number();

        Parrot_pmc_reuse(INTERP, SELF, enum_class_Complex, 0);
        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));
    }

    MULTI void i_add(DEFAULT value) {
        VTABLE_set_number_native(INTERP, SELF,
            SELF.get_number() + VTABLE_get_number(INTERP, value));
    }

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

    VTABLE void i_add_float(FLOATVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            SELF.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

*/

    MULTI PMC *subtract(Complex value, PMC *dest) {
        const FLOATVAL a = SELF.get_number();
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, value));

        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;
    }

    MULTI PMC *subtract(DEFAULT value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
        VTABLE_set_number_native(INTERP, dest,
                SELF.get_number() - VTABLE_get_number(INTERP, value));
        return dest;
    }

    VTABLE PMC *subtract_int(INTVAL value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                SELF.get_number() - (FLOATVAL)value);
        return dest;
    }

    VTABLE PMC *subtract_float(FLOATVAL value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                SELF.get_number() - value);
        return dest;
    }

    MULTI void i_subtract(Complex value) {
        const FLOATVAL a = SELF.get_number();

        Parrot_pmc_reuse(INTERP, SELF, enum_class_Complex, 0);
        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));
    }

    MULTI void i_subtract(DEFAULT value) {
        VTABLE_set_number_native(INTERP, SELF,
            SELF.get_number() - VTABLE_get_number(INTERP, value));
    }

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

    VTABLE void i_subtract_float(FLOATVAL value) {
        VTABLE_set_number_native(INTERP, SELF,
            SELF.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

*/

    MULTI PMC *multiply(Complex value, PMC *dest) {
        Parrot_ex_throw_from_c_args(INTERP, NULL,
            EXCEPTION_INTERNAL_NOT_IMPLEMENTED, "TODO mul<Float, Complex>");
    }

    MULTI PMC *multiply(DEFAULT value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
            SELF.get_number() * VTABLE_get_number(INTERP, value));
        return dest;
    }

    VTABLE PMC *multiply_int(INTVAL value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
            SELF.get_number() * value);
        return dest;
    }

    VTABLE PMC *multiply_float(FLOATVAL value, PMC *dest) {
        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
            SELF.get_number() * value);
        return dest;
    }

    MULTI void i_multiply(Complex value) {
        Parrot_ex_throw_from_c_args(INTERP, NULL,
            EXCEPTION_INTERNAL_NOT_IMPLEMENTED,
            "TODO i_mul<Float, Complex>");
    }

    MULTI void i_multiply(DEFAULT value) {
        VTABLE_set_number_native(INTERP, SELF,
            SELF.get_number() * VTABLE_get_number(INTERP, value));
    }

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

    VTABLE void i_multiply_float(FLOATVAL value) {
        VTABLE_set_number_native(INTERP, SELF, SELF.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

*/

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

        if (FLOAT_IS_ZERO(d))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest, SELF.get_number() / d);
        return dest;
    }

    VTABLE PMC *divide_int(INTVAL value, PMC *dest) {
        if (value == 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest, SELF.get_number() / value);
        return dest;
    }

    VTABLE PMC *divide_float(FLOATVAL value, PMC *dest) {
        if (FLOAT_IS_ZERO(value))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest, SELF.get_number() / value);
        return dest;
    }

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

        if (FLOAT_IS_ZERO(d))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        VTABLE_set_number_native(INTERP, SELF, SELF.get_number() / d);
    }

    VTABLE void i_divide_int(INTVAL value) {
        if (value == 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        VTABLE_set_number_native(INTERP, SELF, SELF.get_number() / value);
    }

    VTABLE void i_divide_float(FLOATVAL value) {
        if (FLOAT_IS_ZERO(value))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        VTABLE_set_number_native(INTERP, SELF, SELF.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

*/

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

        if (FLOAT_IS_ZERO(d))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
        d    = floor(SELF.get_number() / d);

        VTABLE_set_integer_native(INTERP, dest, (INTVAL)d);
        return dest;
    }

    VTABLE PMC *floor_divide_int(INTVAL value, PMC *dest) {
        if (value == 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                floor(SELF.get_number() / value));
        return dest;
    }

    VTABLE PMC *floor_divide_float(FLOATVAL value, PMC *dest) {
        if (FLOAT_IS_ZERO(value))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                floor(SELF.get_number() / value));
        return dest;
    }

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

        if (FLOAT_IS_ZERO(d))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        VTABLE_set_number_native(INTERP, SELF,
                floor(SELF.get_number() / d));
    }

    VTABLE void i_floor_divide_int(INTVAL value) {
        if (value == 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        VTABLE_set_number_native(INTERP, SELF,
                floor(SELF.get_number() / value));
    }

    VTABLE void i_floor_divide_float(FLOATVAL value) {
        if (FLOAT_IS_ZERO(value))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float division by zero");

        VTABLE_set_number_native(INTERP, SELF,
                floor(SELF.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

*/

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

        if (FLOAT_IS_ZERO(d))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float modulus by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                floatval_mod(SELF.get_number(), d));
        return dest;
    }

    VTABLE PMC *modulus_int(INTVAL value, PMC *dest) {
        if (value == 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float modulus by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                floatval_mod(SELF.get_number(), (FLOATVAL)value));
        return dest;
    }

    VTABLE PMC *modulus_float(FLOATVAL value, PMC *dest) {
        if (FLOAT_IS_ZERO(value))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float modulus by zero");

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_number_native(INTERP, dest,
                floatval_mod(SELF.get_number(), value));
        return dest;
    }

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

        if (FLOAT_IS_ZERO(d))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float modulus by zero");

        VTABLE_set_number_native(INTERP, SELF,
                floatval_mod(SELF.get_number(), d));
    }

    VTABLE void i_modulus_int(INTVAL value) {
        if (value == 0)
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float modulus by zero");

        VTABLE_set_number_native(INTERP, SELF,
                floatval_mod(SELF.get_number(), (FLOATVAL)value));
    }

    VTABLE void i_modulus_float(FLOATVAL value) {
        if (FLOAT_IS_ZERO(value))
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_DIV_BY_ZERO,
                "float modulus by zero");

        VTABLE_set_number_native(INTERP, SELF,
                floatval_mod(SELF.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

*/

    VTABLE PMC *neg(PMC *dest) {
        const INTVAL a = -SELF.get_integer();

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_integer_native(INTERP, dest, a);
        return dest;
    }

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

/*

=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

*/

    VTABLE PMC *concatenate(PMC *value, PMC *dest) {
        STRING * const s = Parrot_str_concat(INTERP, SELF.get_string(),
            VTABLE_get_string(INTERP, value));

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_string_native(INTERP, dest, s);
        return dest;
    }

    VTABLE PMC *concatenate_str(STRING *value, PMC *dest) {
        STRING * const s = Parrot_str_concat(INTERP,
            SELF.get_string(), value);

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_string_native(INTERP, dest, s);
        return dest;
    }

    VTABLE void i_concatenate(PMC *value) {
        STRING * const s = SELF.get_string();
        STRING * const v = VTABLE_get_string(INTERP, value);
        SELF.set_string_native(Parrot_str_concat(INTERP, s, v));
    }

    VTABLE void i_concatenate_str(STRING *value) {
        STRING * const s = SELF.get_string();
        SELF.set_string_native(Parrot_str_concat(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

*/

    VTABLE PMC *repeat(PMC *value, PMC *dest) {
        STRING * const s = SELF.get_string();
        const UINTVAL  n = (UINTVAL)VTABLE_get_integer(INTERP, value);

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_string_native(INTERP, dest,
            Parrot_str_repeat(INTERP, s, n));
        return dest;
    }

    VTABLE PMC *repeat_int(INTVAL value, PMC *dest) {
        STRING * const s = SELF.get_string();
        const UINTVAL  n = value;

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_string_native(INTERP, dest,
            Parrot_str_repeat(INTERP, s, n));
        return dest;
    }


    VTABLE void i_repeat(PMC *value) {
        STRING * const s = SELF.get_string();
        const UINTVAL  n = (UINTVAL)VTABLE_get_integer(INTERP, value);
        SELF.set_string_native(Parrot_str_repeat(INTERP, s, n));
    }

    VTABLE void i_repeat_int(INTVAL value) {
        STRING * const s = SELF.get_string();
        const UINTVAL  n = value;
        SELF.set_string_native(Parrot_str_repeat(INTERP, s, n));
    }



/*

=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

*/

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

        return FLOAT_IS_ZERO(diff) ? 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

*/

    MULTI INTVAL cmp_string(PMC *value) {
        return Parrot_str_compare(INTERP, SELF.get_string(),
            VTABLE_get_string(INTERP, value));
    }

/*

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

Returns whether the PMC is equal to C<*value>.

=cut

*/

/*
    MULTI INTVAL is_equal(PMC *value) {
        return (SELF->vtable         == value->vtable
            &&  PMC_data(SELF)       == PMC_data(value));
    }
*/

/*

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

Returns whether the PMC is numerically equal to C<*value>.

=cut

*/

    MULTI INTVAL is_equal_num(PMC *value) {
        return (VTABLE_get_number(INTERP, SELF) ==
                VTABLE_get_number(INTERP, value));
    }

/*

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

Returns whether the PMC has string equality with C<*value>.

=cut

*/

    MULTI INTVAL is_equal_string(PMC *value) {
        return (0 != Parrot_str_equal(INTERP, VTABLE_get_string(INTERP, SELF),
                                          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

*/

    VTABLE PMC *logical_or(PMC *value, PMC *dest) {
        if (SELF.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

*/

    VTABLE PMC *logical_and(PMC *value, PMC *dest) {
        if (SELF.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

*/

    VTABLE PMC *logical_xor(PMC *value, PMC *dest) {
        const INTVAL my_bool    = SELF.get_bool();
        const INTVAL value_bool = VTABLE_get_bool(INTERP, value);

        if (my_bool && ! value_bool)
            return SELF;
        else if (value_bool && ! my_bool)
            return value;

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
        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

*/

    VTABLE PMC *logical_not(PMC *dest) {
        const INTVAL a = ! SELF.get_bool();

        dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));

        VTABLE_set_bool(INTERP, dest, a);
        return dest;
    }

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

/*

=item C<INTVAL defined()>

Always returns true.

=cut

*/

    VTABLE 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

*/

    VTABLE STRING *substr_str(INTVAL offset, INTVAL length) {
        return Parrot_str_substr(INTERP, VTABLE_get_string(INTERP, SELF),
                offset, length);
    }

/*

=item C<void share_ro()>

Sets this PMC as shared and read-only.

=cut

*/
    VTABLE PMC *share_ro() {
        PMC         *ret  = pt_shared_fixup(INTERP, SELF);
        PMC * const _true = Parrot_pmc_new_init_int(INTERP, enum_class_Integer, 1);

        /* first set readonly */
        VTABLE_setprop(INTERP, ret, CONST_STRING(INTERP, "_ro"), _true);

        /* We're sharing this, so make sure it has a PMC_sync */
        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:
 */
