/*
Copyright (C) 2005-2006, The Perl Foundation.
$Id: luanumber.pmc 17096 2007-02-20 20:20:48Z paultcochrane $

=head1 NAME

pmc/luanumber.pmc - Lua Number

=head1 DESCRIPTION

C<LuaNumber> extends C<LuaAny> to provide a class with the behaviour of
the Lua C<Number> type.

=head2 Overloaded Methods

=over 4

=cut

*/

#include "parrot/parrot.h"
#include "pmc_luastring.h"

#define LUA_NUMBER_FMT          "%.14g"

static STRING *luanumber_name;
extern INTVAL dynpmc_LuaBoolean;
extern INTVAL dynpmc_LuaNil;
extern INTVAL dynpmc_LuaNumber;
extern INTVAL dynpmc_LuaString;

extern PMC * find_meth(Interp* interp, PMC *obj, const char *name);


pmclass LuaNumber
    extends LuaAny
    does scalar
    does float
    dynpmc
    group lua_group
    hll Lua
    maps Float {

/* Class initialization. Caches constant strings that will be used later.
*/
    void class_init () {
        if (pass) {
            luanumber_name = const_string(INTERP, "number");
        }
    }

/*

=item C<void init()>

Initializes the number to zero.

=cut

*/
    void init() {
        PMC_num_val(SELF) = 0.0;
    }

/*

=item C<PMC* new_from_string(STRING *rep, INTVAL flags)>

Return a LuaNumber PMC created from a string (Implementation
is based on new_from_string() from Integer PMC).

Allow :

    .const .LuaNumber n = "12.34"

=cut

*/
    PMC* new_from_string (STRING *rep, INTVAL flags) {
        INTVAL type;
        PMC *res;

        type = SELF->vtable->base_type;
        if (flags & PObj_constant_FLAG)
            res = constant_pmc_new(INTERP, type);
        else
            res = pmc_new(INTERP, type);

        PMC_num_val(res) = string_to_num(INTERP, rep);
        return res;
    }

/*

=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<STRING* name()>

Return the string "number".

=cut

*/
    STRING* name () {
        return luanumber_name;
    }

/*

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

/*

=item C<INTVAL get_integer()>

Returns an integer representation of the number (by casting).

=cut

*/
   INTVAL get_integer () {
        return (INTVAL) PMC_num_val(SELF);
   }

/*

=item C<FLOATVAL get_number()>

Returns the value of the number.

=cut

*/
    FLOATVAL get_number () {
        return PMC_num_val(SELF);
    }

/*

=item C<STRING* get_string()>

Returns a Parrot string representation of the number.

=cut

*/
    STRING* get_string () {
        FLOATVAL f = PMC_num_val(SELF);
        return Parrot_sprintf_c(INTERP, LUA_NUMBER_FMT, f);
    }

/*

=item C<void set_integer_native(INTVAL value)>

=cut

*/
    void set_integer_native (INTVAL value) {
        PMC_num_val(SELF) = (FLOATVAL)value;
    }

/*

=item C<void set_number_native(FLOATVAL value)>

=cut

*/
    void set_number_native (FLOATVAL value) {
        PMC_num_val(SELF) = value;
    }

/*

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

=cut

*/
    void set_string_native (STRING *value) {
        VTABLE_morph(INTERP, SELF, dynpmc_LuaString);
        VTABLE_set_string_native(INTERP, SELF, value);
    }

/*

=item C<void increment()>

Increments the number.

=cut

*/
    void increment () {
        PMC_num_val(SELF) ++;
    }

/*

=item C<void decrement()>

Decrements the number.

=cut

*/
    void decrement () {
        PMC_num_val(SELF) --;
    }

/*

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

=cut

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

/*

=item C<void i_neg ()>

=cut

*/
    void i_neg () {
        FLOATVAL a = - DYNSELF.get_number();
        VTABLE_set_number_native(INTERP, SELF, a);
    }

/*

=back

=head2 non-Vtable Methods

=over 4

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

=cut

*/
    PMC* add (PMC* value, PMC* dest) {
MMD_LuaNumber: {
            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;
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_add_LuaNumber(INTERP, SELF, n, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
                return NULL;
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__add");
            if (meth != NULL) {
                dest = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == dest) {
                    dest = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return dest;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return NULL;
        }
    }

/*

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

=cut

*/
    void i_add (PMC* value) {
MMD_LuaNumber: {
            VTABLE_set_number_native(INTERP, SELF,
                DYNSELF.get_number() + VTABLE_get_number(INTERP, value));
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_add_LuaNumber(INTERP, SELF, n);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__add");
            if (meth != NULL) {
                SELF = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == SELF) {
                    SELF = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
        }
    }

/*

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

=cut

*/
    PMC* subtract (PMC* value, PMC* dest) {
MMD_LuaNumber: {
            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;
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_subtract_LuaNumber(INTERP, SELF,
                                                           n, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            }
            return NULL;
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__sub");
            if (meth != NULL) {
                dest = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == dest) {
                    dest = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return dest;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return NULL;
        }
    }

/*

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

=cut

*/
    void i_subtract (PMC* value) {
MMD_LuaNumber: {
            VTABLE_set_number_native(INTERP, SELF,
                DYNSELF.get_number() - VTABLE_get_number(INTERP, value));
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_subtract_LuaNumber(INTERP, SELF, n);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__sub");
            if (meth != NULL) {
                SELF = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == SELF) {
                    SELF = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
        }
    }

/*

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

=cut

*/
    PMC* multiply (PMC* value, PMC* dest) {
MMD_LuaNumber: {
            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;
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_multiply_LuaNumber(INTERP, SELF,
                                                           n, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
                return NULL;
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__mul");
            if (meth != NULL) {
                dest = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == dest) {
                    dest = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return dest;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return NULL;
        }
    }

/*

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

=cut

*/
    void i_multiply (PMC* value) {
MMD_LuaNumber: {
            VTABLE_set_number_native(INTERP, SELF,
                DYNSELF.get_number() * VTABLE_get_number(INTERP, value));
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_multiply_LuaNumber(INTERP, SELF, n);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__mul");
            if (meth != NULL) {
                SELF = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == SELF) {
                    SELF = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
        }
    }

/*

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

=cut

*/
    PMC* divide (PMC* value, PMC* dest) {
MMD_LuaNumber: {
            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;
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_divide_LuaNumber(INTERP, SELF,
                                                         n, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
                return NULL;
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__div");
            if (meth != NULL) {
                dest = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == dest) {
                    dest = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return dest;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return NULL;
        }
    }

/*

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

=cut

*/
    void i_divide (PMC* value) {
MMD_LuaNumber: {
            VTABLE_set_number_native(INTERP, SELF,
                DYNSELF.get_number() / VTABLE_get_number(INTERP, value));
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_divide_LuaNumber(INTERP, SELF, n);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__div");
            if (meth != NULL) {
                SELF = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == SELF) {
                    SELF = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
        }
    }

/*

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

=cut

*/
    PMC* modulus (PMC* value, PMC* dest) {
MMD_LuaNumber: {
            FLOATVAL a = DYNSELF.get_number();
            FLOATVAL b = VTABLE_get_number(INTERP, value);

            if (!dest)
                dest = pmc_new(INTERP, SELF->vtable->base_type);
            VTABLE_set_number_native(INTERP, dest, a - floor(a/b)*b);
            return dest;
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_modulus_LuaNumber(INTERP, SELF,
                                                          n, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
                return NULL;
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__mod");
            if (meth != NULL) {
                dest = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == dest) {
                    dest = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return dest;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return NULL;
        }
    }

/*

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

=cut

*/
    void i_modulus (PMC* value) {
MMD_LuaNumber: {
            FLOATVAL a = DYNSELF.get_number();
            FLOATVAL b = VTABLE_get_number(INTERP, value);

            VTABLE_set_number_native(INTERP, SELF, a - floor(a/b)*b);
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_modulus_LuaNumber(INTERP, SELF, n);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__mod");
            if (meth != NULL) {
                SELF = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == SELF) {
                    SELF = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
        }
    }

/*

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

=cut

*/
    PMC* pow (PMC* value, PMC* dest) {
MMD_LuaNumber: {
            if (!dest)
                dest = pmc_new(INTERP, SELF->vtable->base_type);
            VTABLE_set_number_native(INTERP, dest,
                  pow(DYNSELF.get_number(), VTABLE_get_number(INTERP, value)));
            return dest;
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_pow_LuaNumber(INTERP, SELF, n, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                      "attempt to perform arithmetic on a %s value",
                      string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
                return NULL;
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__pow");
            if (meth != NULL) {
                dest = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == dest) {
                    dest = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return dest;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return NULL;
        }
    }

/*

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

=cut

*/
    void i_pow (PMC* value) {
MMD_LuaNumber: {
            VTABLE_set_number_native(INTERP, SELF,
                  pow(DYNSELF.get_number(), VTABLE_get_number(INTERP, value)));
        }
MMD_LuaString: {
            PMC* n = Parrot_LuaString_tonumber(INTERP, value);
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_pow_LuaNumber(INTERP, SELF, n);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                    "attempt to perform arithmetic on a %s value",
                    string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            }
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__pow");
            if (meth != NULL) {
                SELF = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == SELF) {
                    SELF = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to perform arithmetic on a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
        }
    }

/*

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

=cut

*/
    INTVAL is_equal (PMC* value) {
MMD_LuaNumber: {
            return (INTVAL)(PMC_num_val(SELF) == PMC_num_val(value));
        }
MMD_DEFAULT: {
            return (INTVAL)0;
        }
    }

/*

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

=cut

*/
    INTVAL cmp (PMC* value) {
MMD_LuaNumber: {
            FLOATVAL diff;
            diff = PMC_num_val(SELF) - PMC_num_val(value);
            return diff > 0 ? (INTVAL)1 : diff < 0 ? (INTVAL)-1 : (INTVAL)0;
        }
MMD_DEFAULT: {
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to compare number with %s",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return (INTVAL)0;
        }
    }

/*

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

=cut

*/
    PMC* concatenate (PMC* value,  PMC* dest) {
MMD_LuaNumber: {
            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;
        }
MMD_LuaString: {
            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;
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__concat");
            if (meth != NULL) {
                dest = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == dest) {
                    dest = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return dest;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to concatenate a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
            return NULL;
        }
    }

/*

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

=cut

*/
    void i_concatenate (PMC* value) {
MMD_LuaNumber: {
            STRING* s = DYNSELF.get_string();
            STRING* v = VTABLE_get_string(INTERP, value);
            DYNSELF.set_string_native(string_append(INTERP, s, v));
        }
MMD_LuaString: {
            STRING* s = DYNSELF.get_string();
            STRING* v = VTABLE_get_string(INTERP, value);
            DYNSELF.set_string_native(string_append(INTERP, s, v));
        }
MMD_DEFAULT: {
            PMC *meth = find_meth(INTERP, value, "__concat");
            if (meth != NULL) {
                SELF = Parrot_runops_fromc_args(INTERP, meth, "PPP",
                                                SELF, value);
                if (NULL == SELF) {
                    SELF = pmc_new(INTERP, dynpmc_LuaNil);
                }
                return;
            }
            real_exception(INTERP, NULL, ILL_INHERIT,
                  "attempt to concatenate a %s value",
                  string_to_cstring(INTERP, VTABLE_name(INTERP, value)));
        }
    }

/*

=back

=head2 Specific Methods

=over 4

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

=cut

*/
    METHOD PMC* rawequal (PMC* value) {
        PMC *retval;

        retval = pmc_new(INTERP, dynpmc_LuaBoolean);
        if (SELF->vtable->base_type == value->vtable->base_type
         && PMC_num_val(SELF) == PMC_num_val(value))
            PMC_int_val(retval) = 1;
        else
            PMC_int_val(retval) = 0;
        return retval;
    }

/*

=item C<PMC* tonumber()>

=cut

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

        retval = VTABLE_clone(INTERP, SELF);
        return retval;
    }

}

/*

=back

=head1 AUTHORS

Francois Perrad.

Klaas-Jan Stol.

=cut

*/

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