/*
Copyright (C) 2006-2008, The Perl Foundation.
$Id: /mirror/trunk/languages/WMLScript/pmc/wmlsstring.pmc 35749 2009-01-18T14:13:42.921226Z fperrad  $

=head1 NAME

pmc/wmlsstring.pmc - WMLScript String

=head1 DESCRIPTION

C<WmlsString> extends C<String> to provide a class with the behaviour of
the WMLScript C<String> type.

=head2 Methods

=over 4

=cut

*/

#include "parrot/embed.h"

static INTVAL dynpmc_WmlsBoolean;
static INTVAL dynpmc_WmlsFloat;
static INTVAL dynpmc_WmlsInteger;
static INTVAL dynpmc_WmlsInvalid;
static INTVAL dynpmc_WmlsString;

pmclass WmlsString
    extends String
    provides scalar
    provides string
    dynpmc
    group wmls_group
    hll wmlscript maps String {

/* Class initialization. Caches constant strings that will be used later.
*/
    void class_init() {
        if (pass) {
            dynpmc_WmlsBoolean = pmc_type(INTERP,
              const_string(INTERP, "WmlsBoolean"));
            dynpmc_WmlsFloat = pmc_type(INTERP,
              const_string(INTERP, "WmlsFloat"));
            dynpmc_WmlsInteger = pmc_type(INTERP,
              const_string(INTERP, "WmlsInteger"));
            dynpmc_WmlsInvalid = pmc_type(INTERP,
              const_string(INTERP, "WmlsInvalid"));
            dynpmc_WmlsString = pmc_type(INTERP,
              const_string(INTERP, "WmlsString"));
        }
    }

/*

=item C<PMC* get_class()>

Return the integer 2.

=cut

*/
    VTABLE PMC* get_class() {
        PMC* retval = pmc_new(interp, dynpmc_WmlsInteger);
        PMC_int_val(retval) = 2;
        return retval;
    }

/*

=item C<void increment()>

=cut

*/
    VTABLE void increment() {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInvalid) {
            SELF.morph(dynpmc_WmlsInvalid);
        }
        else if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            const INTVAL a = VTABLE_get_integer(INTERP, trans);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(a);
        }
        else if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            const FLOATVAL a = VTABLE_get_number(INTERP, trans);
            SELF.morph(dynpmc_WmlsFloat);
            SELF.set_number_native(a);
        }
        SELF.increment();
    }

/*

=item C<void decrement()>

=cut

*/
    VTABLE void decrement() {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInvalid) {
            SELF.morph(dynpmc_WmlsInvalid);
        }
        else if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            const INTVAL a = VTABLE_get_integer(INTERP, trans);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(a);
        }
        else if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            const FLOATVAL a = VTABLE_get_number(INTERP, trans);
            SELF.morph(dynpmc_WmlsFloat);
            SELF.set_number_native(a);
        }
        SELF.decrement();
    }

/*

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

=item C<void i_absolute()>

=cut

*/
    VTABLE PMC* absolute(PMC* dest) {
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    VTABLE void i_absolute() {
        SELF.morph(dynpmc_WmlsInvalid);
    }

/*

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

=item C<void i_neg()>

=cut

*/
    VTABLE PMC* neg(PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            PMC_int_val(dest) = - VTABLE_get_integer(INTERP, trans);
            return dest;
        }
        if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            FLOATVAL result = - VTABLE_get_number(INTERP, trans);
            dest = pmc_new(INTERP, dynpmc_WmlsFloat);
            VTABLE_set_number_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    VTABLE void i_neg() {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(- VTABLE_get_integer(INTERP, trans));
        }
        else if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            SELF.morph(dynpmc_WmlsFloat);
            SELF.set_number_native(- VTABLE_get_number(INTERP, trans));
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

=item C<void i_bitwise_not()>

=cut

*/
    VTABLE PMC* bitwise_not(PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"), "->P",
            &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            PMC_int_val(dest) = ~ VTABLE_get_integer(INTERP, trans);
            return dest;
        }

        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    VTABLE void i_bitwise_not() {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(~ VTABLE_get_integer(INTERP, trans));
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

=item C<void i_logical_not()>

=cut

*/
    VTABLE PMC* logical_not(PMC* dest) {
        dest = pmc_new(INTERP, dynpmc_WmlsBoolean);
        VTABLE_set_bool(INTERP, dest, ! SELF.get_bool());
        return dest;
    }

    VTABLE void i_logical_not() {
        INTVAL result = ! SELF.get_bool();
        SELF.morph(dynpmc_WmlsBoolean);
        SELF.set_integer_native(result);
    }

/*

=back

=head2 non-Vtable Methods

=over 4

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

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

=cut

*/
    MULTI PMC* add(WmlsString value, PMC* dest) {
        STRING* result = string_concat(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value), 0);
        dest = pmc_new(INTERP, dynpmc_WmlsString);
        VTABLE_set_string_native(INTERP, dest, result);
        return dest;
    }

    MULTI PMC* add(WmlsInteger value, PMC* dest) {
        STRING* result = string_concat(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value), 0);
        dest = pmc_new(INTERP, dynpmc_WmlsString);
        VTABLE_set_string_native(INTERP, dest, result);
        return dest;
    }

    MULTI PMC* add(WmlsBoolean value, PMC* dest) {
        STRING* result = string_concat(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value), 0);
        dest = pmc_new(INTERP, dynpmc_WmlsString);
        VTABLE_set_string_native(INTERP, dest, result);
        return dest;
    }

    MULTI PMC* add(WmlsFloat value, PMC* dest) {
        STRING* result = string_concat(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value), 0);
        dest = pmc_new(INTERP, dynpmc_WmlsString);
        VTABLE_set_string_native(INTERP, dest, result);
        return dest;
    }

    MULTI PMC* add(DEFAULT value, PMC* dest) {
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI void i_add(WmlsString value) {
        STRING* result = string_append(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
        SELF.set_string_native(result);
    }

    MULTI void i_add(WmlsInteger value) {
        STRING* result = string_append(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
        SELF.set_string_native(result);
    }

    MULTI void i_add(WmlsBoolean value) {
        STRING* result = string_append(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
        SELF.set_string_native(result);
    }

    MULTI void i_add(WmlsFloat value) {
        STRING* result = string_append(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
        SELF.set_string_native(result);
    }

    MULTI void i_add(DEFAULT value) {
        SELF.morph(dynpmc_WmlsInvalid);
    }

/*

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

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

=cut

*/
    MULTI PMC* subtract(WmlsString value, PMC* dest) {
        PMC *trans1, *trans2;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans1);

        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseNumber"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans1)
                          - VTABLE_get_integer(INTERP, trans2);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        if (trans1->vtable->base_type != dynpmc_WmlsInvalid
          && trans2->vtable->base_type != dynpmc_WmlsInvalid) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans1)
                            - VTABLE_get_number(INTERP, trans2);
            dest = pmc_new(INTERP, dynpmc_WmlsFloat);
            VTABLE_set_number_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* subtract(WmlsInteger value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          - VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* subtract(WmlsBoolean value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          - VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* subtract(WmlsFloat value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans)
                            - VTABLE_get_number(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsFloat);
            VTABLE_set_number_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* subtract(DEFAULT value, PMC* dest) {
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI void i_subtract(WmlsString value) {
        PMC *trans1, *trans2;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans1);

        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseNumber"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans1)
                          - VTABLE_get_integer(INTERP, trans2);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else if (trans1->vtable->base_type != dynpmc_WmlsInvalid
               && trans2->vtable->base_type != dynpmc_WmlsInvalid) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans1)
                            - VTABLE_get_number(INTERP, trans2);
            SELF.morph(dynpmc_WmlsFloat);
            SELF.set_number_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_subtract(WmlsInteger value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          - VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_subtract(WmlsBoolean value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          - VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_subtract(WmlsFloat value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans)
                            - VTABLE_get_number(INTERP, value);
            SELF.morph(dynpmc_WmlsFloat);
            SELF.set_number_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_subtract(DEFAULT value) {
        SELF.morph(dynpmc_WmlsInvalid);
    }

/*

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

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

=cut

*/
    MULTI PMC* multiply(WmlsString value, PMC *dest) {
        PMC *trans1, *trans2;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans1);

        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseNumber"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans1)
                          * VTABLE_get_integer(INTERP, trans2);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        if (trans1->vtable->base_type != dynpmc_WmlsInvalid
          && trans2->vtable->base_type != dynpmc_WmlsInvalid) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans1)
                            * VTABLE_get_number(INTERP, trans2);
            dest = pmc_new(INTERP, dynpmc_WmlsFloat);
            VTABLE_set_number_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* multiply(WmlsInteger value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          * VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* multiply(WmlsBoolean value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          * VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* multiply(WmlsFloat value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans)
                            * VTABLE_get_number(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsFloat);
            VTABLE_set_number_native(INTERP, dest, result);
            return dest;
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* multiply(DEFAULT value, PMC *dest) {
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI void i_multiply(WmlsString value) {
        PMC *trans1, *trans2;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseNumber"),
            "->P", &trans1);

        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseNumber"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans1)
                          * VTABLE_get_integer(INTERP, trans2);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else if (trans1->vtable->base_type != dynpmc_WmlsInvalid
               && trans2->vtable->base_type != dynpmc_WmlsInvalid) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans1)
                            * VTABLE_get_number(INTERP, trans2);
            SELF.morph(dynpmc_WmlsFloat);
            SELF.set_number_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_multiply(WmlsInteger value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          * VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_multiply(WmlsBoolean value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          * VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_multiply(WmlsFloat value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            FLOATVAL result = VTABLE_get_number(INTERP, trans)
                            * VTABLE_get_number(INTERP, value);
            SELF.morph(dynpmc_WmlsFloat);
            SELF.set_number_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_multiply(DEFAULT value) {
        SELF.morph(dynpmc_WmlsInvalid);
    }

/*

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

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

=cut

*/
    MULTI PMC* divide(WmlsString value, PMC *dest) {
        PMC *trans1, *trans2;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans1);

        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseFloat"),
            "->P", &trans2);

        if (trans1->vtable->base_type != dynpmc_WmlsInvalid
        &&  trans2->vtable->base_type != dynpmc_WmlsInvalid) {
            FLOATVAL d = VTABLE_get_number(INTERP, trans2);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans1) / d;
                dest = pmc_new(INTERP, dynpmc_WmlsFloat);
                VTABLE_set_number_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* divide(WmlsInteger value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            FLOATVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans) / d;
                dest = pmc_new(INTERP, dynpmc_WmlsFloat);
                VTABLE_set_number_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* divide(WmlsBoolean value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            FLOATVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans) / d;
                dest = pmc_new(INTERP, dynpmc_WmlsFloat);
                VTABLE_set_number_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* divide(WmlsFloat value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            FLOATVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans) / d;
                dest = pmc_new(INTERP, dynpmc_WmlsFloat);
                VTABLE_set_number_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* divide(DEFAULT value, PMC *dest) {
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI void i_divide(WmlsString value) {
        PMC *trans1, *trans2;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans1);

        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseFloat"),
            "->P", &trans2);

        if (trans1->vtable->base_type != dynpmc_WmlsInvalid
        &&  trans2->vtable->base_type != dynpmc_WmlsInvalid) {
            FLOATVAL d = VTABLE_get_number(INTERP, trans2);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans1) / d;
                SELF.morph(dynpmc_WmlsFloat);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_divide(WmlsInteger value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            FLOATVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans) / d;
                SELF.morph(dynpmc_WmlsFloat);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_divide(WmlsBoolean value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            FLOATVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans) / d;
                SELF.morph(dynpmc_WmlsFloat);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_divide(WmlsFloat value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsFloat) {
            FLOATVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0.0) {
                FLOATVAL result = VTABLE_get_number(INTERP, trans) / d;
                SELF.morph(dynpmc_WmlsFloat);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_divide(DEFAULT value) {
        SELF.morph(dynpmc_WmlsInvalid);
    }

/*

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

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

=cut

*/
    MULTI PMC* floor_divide(WmlsString value, PMC *dest) {
        PMC *trans1, *trans2;

        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans1);
        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_integer(INTERP, trans2);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans1) / d;
                dest = pmc_new(INTERP, dynpmc_WmlsInteger);
                VTABLE_set_integer_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* floor_divide(WmlsInteger value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) / d;
                dest = pmc_new(INTERP, dynpmc_WmlsInteger);
                VTABLE_set_integer_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* floor_divide(WmlsBoolean value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) / d;
                dest = pmc_new(INTERP, dynpmc_WmlsInteger);
                VTABLE_set_integer_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* floor_divide(DEFAULT value, PMC *dest) {
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI void i_floor_divide(WmlsString value) {
        PMC *trans1, *trans2;

        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans1);
        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_integer(INTERP, trans2);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans1) / d;
                SELF.morph(dynpmc_WmlsInteger);
                SELF.set_integer_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_floor_divide(WmlsInteger value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) / d;
                SELF.morph(dynpmc_WmlsInteger);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_floor_divide(WmlsBoolean value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) / d;
                SELF.morph(dynpmc_WmlsInteger);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_floor_divide(DEFAULT value) {
        SELF.morph(dynpmc_WmlsInvalid);
    }

/*

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

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

=cut

*/
    MULTI PMC* modulus(WmlsString value, PMC *dest) {
        PMC *trans1, *trans2;

        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans1);
        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_integer(INTERP, trans2);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans1) % d;
                dest = pmc_new(INTERP, dynpmc_WmlsInteger);
                VTABLE_set_integer_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* modulus(WmlsInteger value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) % d;
                dest = pmc_new(INTERP, dynpmc_WmlsInteger);
                VTABLE_set_integer_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* modulus(WmlsBoolean value, PMC *dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) % d;
                dest = pmc_new(INTERP, dynpmc_WmlsInteger);
                VTABLE_set_integer_native(INTERP, dest, result);
                return dest;
            }
        }
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI PMC* modulus(DEFAULT value, PMC *dest) {
        return pmc_new(INTERP, dynpmc_WmlsInvalid);
    }

    MULTI void i_modulus(WmlsString value) {
        PMC *trans1, *trans2;

        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans1);
        Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
            "->P", &trans2);

        if (trans1->vtable->base_type == dynpmc_WmlsInteger
        &&  trans2->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_integer(INTERP, trans2);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans1) % d;
                SELF.morph(dynpmc_WmlsInteger);
                SELF.set_integer_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_modulus(WmlsInteger value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) % d;
                SELF.morph(dynpmc_WmlsInteger);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_modulus(WmlsBoolean value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);

        if (trans->vtable->base_type == dynpmc_WmlsInteger) {
            INTVAL d = VTABLE_get_number(INTERP, value);
            if (d != 0) {
                INTVAL result = VTABLE_get_integer(INTERP, trans) % d;
                SELF.morph(dynpmc_WmlsInteger);
                SELF.set_number_native(result);
            }
            else {
                SELF.morph(dynpmc_WmlsInvalid);
            }
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

    MULTI void i_modulus(DEFAULT value) {
        SELF.morph(dynpmc_WmlsInvalid);
    }

/*

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

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

=cut

*/
    VTABLE PMC* bitwise_or(PMC* value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          | VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        else {
            return pmc_new(INTERP, dynpmc_WmlsInvalid);
        }
    }

    VTABLE void i_bitwise_or(PMC* value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          | VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

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

=cut

*/
    VTABLE PMC* bitwise_and(PMC* value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          & VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        else {
            return pmc_new(INTERP, dynpmc_WmlsInvalid);
        }
    }

    VTABLE void i_bitwise_and(PMC* value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          & VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

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

=cut

*/
    VTABLE PMC* bitwise_xor(PMC* value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          ^ VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        else {
            return pmc_new(INTERP, dynpmc_WmlsInvalid);
        }
    }

    VTABLE void i_bitwise_xor(PMC* value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          ^ VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

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

=cut

*/
    VTABLE PMC* bitwise_shr(PMC* value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          >> VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        else {
            return pmc_new(INTERP, dynpmc_WmlsInvalid);
        }
    }

    VTABLE void i_bitwise_shr(PMC* value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          >> VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

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

=cut

*/
    VTABLE PMC* bitwise_lsr(PMC* value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          >> VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        else {
            return pmc_new(INTERP, dynpmc_WmlsInvalid);
        }
    }

    VTABLE void i_bitwise_lsr(PMC* value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          >> VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

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

=cut

*/
    VTABLE PMC* bitwise_shl(PMC* value, PMC* dest) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          << VTABLE_get_integer(INTERP, value);
            dest = pmc_new(INTERP, dynpmc_WmlsInteger);
            VTABLE_set_integer_native(INTERP, dest, result);
            return dest;
        }
        else {
            return pmc_new(INTERP, dynpmc_WmlsInvalid);
        }
    }

    VTABLE void i_bitwise_shl(PMC* value) {
        PMC *trans;
        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &trans);
        if (value->vtable->base_type == dynpmc_WmlsString) {
            Parrot_PCCINVOKE(interp, value, const_string(interp, "parseInt"),
                    "->P", &value);
        }
        if (trans->vtable->base_type == dynpmc_WmlsInteger
          && (value->vtable->base_type == dynpmc_WmlsInteger
            || value->vtable->base_type == dynpmc_WmlsBoolean)) {
            INTVAL result = VTABLE_get_integer(INTERP, trans)
                          << VTABLE_get_integer(INTERP, value);
            SELF.morph(dynpmc_WmlsInteger);
            SELF.set_integer_native(result);
        }
        else {
            SELF.morph(dynpmc_WmlsInvalid);
        }
    }

/*

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

=cut

*/
    MULTI INTVAL is_equal(WmlsString value) {
        return !string_equal(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

    MULTI INTVAL is_equal(WmlsInteger value) {
        return !string_equal(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

    MULTI INTVAL is_equal(WmlsBoolean value) {
        return !string_equal(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

    MULTI INTVAL is_equal(WmlsFloat value) {
        return !string_equal(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

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

/*

=item C<PMC* cmp(PMC *value)>

=cut

*/
    MULTI INTVAL cmp(WmlsString value) {
        return string_compare(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

    MULTI INTVAL cmp(WmlsInteger value) {
        return string_compare(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

    MULTI INTVAL cmp(WmlsBoolean value) {
        return string_compare(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

    MULTI INTVAL cmp(WmlsFloat value) {
        return string_compare(INTERP,
            SELF.get_string(), VTABLE_get_string(INTERP, value));
    }

    MULTI INTVAL cmp(DEFAULT value) {
        return 4;
    }

/*

=back

=head2 Specific Methods

=over 4

=item C<PMC* parseInt()>

=cut

*/
    METHOD PMC* parseInt() {
        PMC    *retval;
        STRING *rep;
        char   *s1;
        char   *s2;
        INTVAL  d;

        rep = SELF.get_string();
        s1 = string_to_cstring(INTERP, rep);
        d  = strtol(s1, &s2, 10);

        if (s1 != s2 && (*s2 == '\0' || isspace((unsigned char)*s2))) {
            retval = pmc_new(INTERP, dynpmc_WmlsInteger);
            PMC_int_val(retval) = d;
        }
        else
            retval = pmc_new(INTERP, dynpmc_WmlsInvalid);

        string_cstring_free(s1);

        RETURN(PMC *retval);
    }

/*

=item C<PMC* parseFloat()>

=cut

*/
    METHOD PMC* parseFloat() {
        PMC     *retval;
        STRING  *rep;
        char    *s1;
        char    *s2;
        FLOATVAL d;

        rep = SELF.get_string();
        s1 = string_to_cstring(INTERP, rep);
        d  = strtod(s1, &s2);

        if (s1 != s2 && (*s2 == '\0' || isspace((unsigned char)*s2))
        && (fabs(d) < 3.40282347e+38)) {
            retval = pmc_new(INTERP, dynpmc_WmlsFloat);
            if (fabs(d) < 1.17549435e-38)
                d = 0.0;

            VTABLE_set_number_native(INTERP, retval, d);
        }
        else
            retval = pmc_new(INTERP, dynpmc_WmlsInvalid);

        string_cstring_free(s1);

        RETURN(PMC *retval);
    }

/*

=item C<PMC* parseNumber()>

=cut

*/
    METHOD PMC* parseNumber() {
        PMC    *retval;

        Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseInt"),
            "->P", &retval);

        if (retval->vtable->base_type == dynpmc_WmlsInvalid)
            Parrot_PCCINVOKE(interp, SELF, const_string(interp, "parseFloat"),
                "->P", &retval);

        RETURN(PMC *retval);
    }


}

/*

=back

=cut

*/


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