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

=head1 NAME

pmc/luastring.pmc - Lua String

=head1 DESCRIPTION

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

=head2 Overloaded Methods

=over 4

=cut

*/

#include "parrot/parrot.h"
#include "pmc_luanumber.h"

static STRING *luastring_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 LuaString
    extends LuaAny
    does scalar
    does string
    dynpmc
    group lua_group
    hll Lua
    maps String {

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

/*

=item C<void init()>

Initializes the string.

=cut

*/
    void init () {
        PMC_str_val(SELF) =
            string_make_empty(INTERP, enum_stringrep_one, 0);
        PObj_custom_mark_SET(SELF);
    }

/*

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

Allow :

    .const .LuaString s = "Hello World!"

=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_str_val(res) = string_copy(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<void mark()>

Marks the string as live.

=cut

*/
    void mark () {
        if(PMC_str_val(SELF))
            pobject_lives(INTERP, (PObj *)PMC_str_val(SELF));
    }

/*

=item C<PMC* clone()>

Creates a copy of the string.

=cut

*/
    PMC* clone () {
        PMC* dest = pmc_new_noinit(INTERP, SELF->vtable->base_type);
        PObj_custom_mark_SET(dest);
        PMC_str_val(dest) = string_copy(INTERP,PMC_str_val(SELF));
        return dest;
    }

/*

=item C<STRING* get_string()>

Returns the string itself.

=cut

*/
    STRING* get_string () {
        return (STRING*) PMC_str_val(SELF);
    }

/*

=item C<STRING* name()>

Return the string "string".

=cut

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

/*

=item C<void set_integer_native (INTVAL value)>

=cut

*/
    void set_number_native(FLOATVAL value) {
        VTABLE_morph(INTERP, SELF, dynpmc_LuaNumber);
        VTABLE_set_number_native(INTERP, SELF, value);
    }

/*

=item C<void set_number_native(FLOATVAL value)>

=cut

*/
    void set_number_native (FLOATVAL value) {
        VTABLE_morph(INTERP, SELF, dynpmc_LuaNumber);
        VTABLE_set_number_native(INTERP, SELF, value);
    }

/*

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

Sets the value of the string to that of the specified C<string>.

=cut

*/
    void set_string_native (STRING* value) {
        PMC_str_val(SELF) = value;
    }

/*

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

=cut

*/
    PMC* neg (PMC * dest) {
        PMC* n = SELF.tonumber();
        if (n->vtable->base_type == dynpmc_LuaNumber) {
            return Parrot_LuaNumber_neg(INTERP, n, dest);
        }
        else {
            real_exception(INTERP, NULL, ILL_INHERIT,
                    "attempt to perform arithmetic on a %s value",
                    string_to_cstring(INTERP, SELF.name()));
            return NULL;
        }
    }

/*

=item C<void i_neg ()>

=cut

*/
    void i_neg() {
        PMC* n = SELF.tonumber();
        if (n->vtable->base_type == dynpmc_LuaNumber) {
            Parrot_LuaNumber_i_neg(INTERP, n);
        }
        else {
            real_exception(INTERP, NULL, ILL_INHERIT,
                    "attempt to perform arithmetic on a %s value",
                    string_to_cstring(INTERP, SELF.name()));
        }
    }

/*

=item C<INTVAL elements ()>

Return length of the string.

=cut

*/
    INTVAL elements () {
        return string_length(INTERP, PMC_str_val(SELF));
    }

/*

=item C<void freeze(visit_info *info)>

Used to archive the string.

=cut

*/
    void freeze(visit_info *info) {
        IMAGE_IO *io = info->image_io;
        SUPER(info);
        VTABLE_push_string(INTERP, io, PMC_str_val(SELF));
    }

/*

=item C<void thaw(visit_info *info)>

Used to unarchive the string.

=cut

*/
    void thaw(visit_info *info) {
        IMAGE_IO *io = info->image_io;
        SUPER(info);
        if (info->extra_flags == EXTRA_IS_NULL)
            PMC_str_val(SELF) = VTABLE_shift_string(INTERP, io);
    }

/*

=back

=head2 non-Vtable Methods

=over 4

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

=cut

*/
    PMC* add (PMC* value, PMC* dest) {
MMD_LuaNumber: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_add_LuaNumber(INTERP, n, value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                return NULL;
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_add_LuaString(INTERP, n, value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_add_LuaNumber(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_add_LuaString(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_subtract_LuaNumber(INTERP, n,
                                                           value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                return NULL;
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_subtract_LuaString(INTERP, n,
                                                           value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_subtract_LuaNumber(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_subtract_LuaString(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_multiply_LuaNumber(INTERP, n,
                                                           value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                return NULL;
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_multiply_LuaString(INTERP, n,
                                                           value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_multiply_LuaNumber(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_multiply_LuaString(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_divide_LuaNumber(INTERP, n,
                                                         value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                return NULL;
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_divide_LuaString(INTERP, n,
                                                         value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_divide_LuaNumber(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_divide_LuaString(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_modulus_LuaNumber(INTERP, n,
                                                          value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                return NULL;
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_modulus_LuaString(INTERP, n,
                                                          value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_modulus_LuaNumber(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_modulus_LuaString(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_pow_LuaNumber(INTERP, n, value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                return NULL;
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                return Parrot_LuaNumber_pow_LuaString(INTERP, n, value, dest);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
                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: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_pow_LuaNumber(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
MMD_LuaString: {
            PMC* n = SELF.tonumber();
            if (n->vtable->base_type == dynpmc_LuaNumber) {
                Parrot_LuaNumber_i_pow_LuaString(INTERP, n, value);
            }
            else {
                real_exception(INTERP, NULL, ILL_INHERIT,
                        "attempt to perform arithmetic on a %s value",
                        string_to_cstring(INTERP, SELF.name()));
            }
        }
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)>

Compares the string with C<value>; returns true if
they match.

=cut

*/
    INTVAL is_equal (PMC* value) {
MMD_LuaString: {
            STRING *s = PMC_str_val(SELF);
            STRING *v = VTABLE_get_string(INTERP, value);
            return (INTVAL)(0 == string_equal(INTERP, s, v));
        }
MMD_DEFAULT: {
            return (INTVAL)0;
        }
    }

/*

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

Compares the string with C<value>; returns -1 if the
string is smaller, 0 if they are equal, and 1 if C<value>
is smaller.

Throws an exception unless C<value> is a LuaString.

=cut

*/
    INTVAL cmp (PMC* value) {
MMD_LuaString: {
            STRING *s = PMC_str_val(SELF);
            STRING *v = VTABLE_get_string(INTERP, value);
            return string_compare(INTERP, s, v);
        }
MMD_DEFAULT: {
            real_exception(INTERP, NULL, ILL_INHERIT,
                    "attempt to compare string 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 *get_metatable()>

=cut

*/
    METHOD PMC* get_metatable() {
        PMC *retval = Parrot_find_global_cur(INTERP,
                             const_string(INTERP, "mt_string"));
        if (retval != NULL)
            return retval;
        return pmc_new(INTERP, dynpmc_LuaNil);
    }

/*

=item C<PMC* len()>


=cut

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

        retval = pmc_new(INTERP, dynpmc_LuaNumber);
        PMC_num_val(retval) = VTABLE_elements(INTERP, SELF);
        return retval;
    }

/*

=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
         && 0 == string_equal(INTERP, PMC_str_val(SELF), PMC_str_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;
        STRING *rep;
        FLOATVAL d;
        char *s1;
        char *s2;

        rep = VTABLE_get_string(INTERP, SELF);
        s1 = string_to_cstring(INTERP, rep);
        d = strtod(s1, &s2);
        if (s1 != s2) {  /* at least one valid digit? */
            while (isspace((unsigned char)(*s2)))
                s2++;  /* skip trailing spaces */
            if (*s2 == '\0') {  /* no invalid trailing characters? */
                retval = pmc_new(INTERP, dynpmc_LuaNumber);
                PMC_num_val(retval) = d;
                return retval;
            }
        }
        retval = pmc_new(INTERP, dynpmc_LuaNil);
        return retval;
    }

/*

=item C<PMC* tobase(INTVAL base)>

=cut

*/
    METHOD PMC* tobase(INTVAL base) {
        PMC *retval;
        STRING *rep;
        unsigned long n;
        char *s1;
        char *s2;

        rep = VTABLE_get_string(INTERP, SELF);
        s1 = string_to_cstring(INTERP, rep);
        n = strtoul(s1, &s2, base);
        if (s1 != s2) {  /* at least one valid digit? */
            while (isspace((unsigned char)(*s2)))
                s2++;  /* skip trailing spaces */
            if (*s2 == '\0') {  /* no invalid trailing characters? */
                retval = pmc_new(INTERP, dynpmc_LuaNumber);
                PMC_num_val(retval) = n;
                return retval;
            }
        }
        retval = pmc_new(INTERP, dynpmc_LuaNil);
        return retval;
    }

}

/*

=back

=head1 AUTHORS

Francois Perrad.

Klaas-Jan Stol.

=cut

*/

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