NAME ^

src/pmc/perl6str.pmc - Perl 6 Strings

DESCRIPTION ^

Perl6Str extends String to provide Perl 6-specific string numifying behavior.

Methods ^

INTVAL get_integer()

Returns the value of a Perl 6 string as an integer. For now we just call get_number() and return that as an integer.

FLOATVAL get_number()

Returns the value of a Perl 6 string as a number. Currently this routine understands the "0x", "0d", "0o", and "0b" radix forms, as well as exponents and underscores between pairs of digits.

void increment()

void decrement()

Increment/decrement the string magically according to S03 rules.

These implementations are very ASCII oriented. They assume that the alphabet is contiguous and that there aren't any other characters on either side of the letters or digits that return true for isalpha() or isdigit() respectively.

*/

    VTABLE void increment() {
        STRING     *str        = PMC_str_val(SELF);
        const char *start      = str->strstart;
        const char * const end = start + string_length(INTERP, str);

        /* pointer to the substring we're going to increment */
        char       *substr;

        /* length of the substring */
        INTVAL      len;

        INTVAL i, carry;

        /* start of the current incrementable substring */
        const char *s = start;

        /* end of the current incrementable substring */
        const char *e = start;

        /* start of the previous incrementable substring */
        const char *ps = 0;

        /* end of the previous incrementable substring */
        const char *pe = 0;

        /* find the portion of the string to increment */
        while (s < end) {
            while (!isalnum((unsigned char)*s) && s < end)
                s++;

            e = s;

            while (isalnum((unsigned char)*e) && e < end)
                e++;

            if (!(e < end))
                break;

            ps = s;
            pe = e;
            s = e;
        }

        if (ps == 0 || *pe != '.') {
            len    = e - s;
            substr = (char *)s;
        }
        else {
            len    = pe - ps;
            substr = (char*)ps;
        }

        /* Actual increment */
        for (i = len - 1, carry = 1; i >= 0 && carry; i--) {
            if (isdigit((unsigned char)substr[i])) {

                if (++substr[i] <= '9') {
                    carry = 0;
                }
                else {
                    substr[i] = '0';
                    carry     = 1;
                }
            }
            else {
                if (isalpha((unsigned char)++substr[i])) {
                    carry = 0;
                }
                else {
                    substr[i] -= 'z' - 'a' + 1;
                    carry      = 1;
                }
            }
        }

        /* If there's a carry, extend the string */
        if (carry && len > 0) {
            /* start index of incrementable portion */
            INTVAL a = substr - start;

            /* length to end of string */
            INTVAL b = str->strlen - a;

            STRING *rep = string_substr(INTERP, str, a, b, NULL, 0);
            INTVAL  c   = '1';

            if (isalpha((unsigned char)start[a]))
                c = start[a];

            string_replace(INTERP, str, a + 1, b, rep, 0);
            string_replace(INTERP, str, a, 1, string_chr(INTERP, c), 0);
        }
    }


    VTABLE void decrement() {
        STRING     *str        = PMC_str_val(SELF);
        const char *start      = str->strstart;
        const char * const end = start + string_length(INTERP, str);

        /* pointer to the substring we're going to decrement */
        char *substr;

        /* length of the substring */
        INTVAL len;

        INTVAL i, steal;

        /* start of the current decrementable substring */
        const char *s = start;

        /* end of the current decrementable substring */
        const char *e = start;

        /* start of the previous decrementable substring */
        const char *ps = 0;

        /* end of the previous decrementable substring */
        const char *pe = 0;

        /* Find the portion of the string to decrement */
        while (s < end) {
            while (!isalnum((unsigned char)*s) && s < end)
                s++;

            e = s;

            while (isalnum((unsigned char)*e) && e < end)
                e++;

            if (!(e < end))
                break;

            ps = s;
            pe = e;
            s = e;
        }

        if (ps == 0 || *pe != '.') {
            len    = e - s;
            substr = (char *)s;
        }
        else {
            len    = pe - ps;
            substr = (char *)ps;
        }

        /* Check if we've bottomed out on decrementing */
        for (i = 0; i < len; i++) {
            if (substr[i] != 'a' && substr[i] != 'A' && substr[i] != '0')
                break;
        }

        if (i == len)
            return;

        /* Actual decrement */
        for (i = len - 1, steal = 1; i >= 0 && steal; i--) {
            if (isdigit((unsigned char)substr[i])) {
                if (--substr[i] >= '0') {
                    steal = 0;
                }
                else {
                    substr[i] = '9';
                    steal     = 1;
                }
            }
            else {
                if (isalpha((unsigned char)--substr[i])) {
                    steal = 0;
                }
                else {
                    substr[i] += 'z' - 'a' + 1;
                    steal      = 1;
                }
            }
        }
    }
}

/*


parrot