/*
=head1 NAME

CodeString - object to build (PIR) code segments

=head1 SYNOPSIS

    .local pmc code
    code = new 'CodeString'

    code.emit("   $P0 = %0 * %1", '$P21', '3')
    code.emit("  %l:", 'l' => 'label')

    print code

=head1 DESCRIPTION

C<CodeString> is a class intended to simplify the process of
emitting code strings.  Ideally this will eventually
become a form of "CodeBuffer" that is more efficient
than string concatenation, but for now it works well
enough for me.

The primary method for C<CodeString> objects is C<emit>,
which appends a line (or lines) of code to the string
according to a format parameter.  The line can contain
substitution markers (ala printf) that indicate where
other parameters to the call should be placed.

Note that C<CodeString> is just a subclass of Parrot's
native C<String> class, so it's easy to combine CodeString
objects with other strings outside of the C<emit> method.

=head2 Functions

=over 4

=item C<_onload()>

Initializes the C<CodeString> class.

=cut

*/

/* RubyString.pmc
 *  Copyright (C) 2006, The Perl Foundation.
 *  SVN Info
 *     $Id: codestring.pmc 17093 2007-02-20 20:08:29Z paultcochrane $
 *  Overview:
 *     These are the vtable functions for the CodeString base class
 *  Data Structure and Algorithms:
 *  History:
 *  Notes:
 *     Please remove unneeded entries.
 *  References:
 */

#include "parrot/parrot.h"


pmclass CodeString extends String does string dynpmc group pge
{
    void init () {
        Parrot_String_init(interp, SELF);
    }

            /*
    void class_init () {
        if (pass) {
            PMC *global_serno = pmc_new(INTERP, enum_class_Integer);
            PMC * const cur_ns = CONTEXT(INTERP->ctx)->current_namespace;

            PIO_printf(interp, "%d %Ss, %d\n", cur_ns, (STRING*)PMC_data(cur_ns), global_serno);
            VTABLE_set_integer_native(INTERP, global_serno, 10);
            Parrot_set_global(INTERP, cur_ns, string_from_const_cstring(INTERP, "$!serno", 0), global_serno);
        }
    }
            */

/*

=item C<emit(string fmt [, pmc args ] [, pmc hash ])>

Add a line to a C<CodeString> object according to C<fmt>.
The C<fmt> string can contain any number of "%-replacements"
which are replaced by the corresponding values from C<args>
or C<hash> prior to being appended to the string.  (Here
C<args> is a slurpy array, and C<hash> is a slurpy hash.)

The currently defined replacements include:

    %0 %1 ... %9     the value from the args array at index 0..9
    %,               the values of the args array separated by commas
    %%               a percent sign

A percent-sign followed by any other character that is a hash
key receives the value of the hash element.

A newline is automatically added to the end of the fmt.

=cut

*/
    PMETHOD void emit(STRING *orig_format, PMC *args :slurpy, PMC *named_args :slurpy :named) {
        INTVAL position = 0;
        INTVAL repl_len = 0;
        STRING *format;
        STRING *key;
        STRING *repl;
        STRING *PERCENT = string_from_const_cstring(INTERP, "%", 0);
        STRING *COMMA   = string_from_const_cstring(INTERP, ",", 0);
        STRING *NEWLINE = string_from_const_cstring(INTERP, "\n", 0);

        format = string_copy(interp, orig_format);

        position = string_str_index(interp, format, PERCENT, position);
        while ( position > 0 )
        {
            key = string_substr(interp, format, position + 1, 1, NULL, 0);
            /* named substitution  %position */
            if ( named_args != PMCNULL && VTABLE_exists_keyed_str(interp, named_args, key)) {
                repl = VTABLE_get_string_keyed_str(interp, named_args, key);
            }
            /* positional substutution  %7 */
            else if (Parrot_string_is_cclass(interp, enum_cclass_numeric, format, position + 1)) {
                repl = VTABLE_get_string_keyed_int(interp, args, string_to_int(interp, key));
            }
            /* %, */
            else if (string_equal(interp, key, COMMA)) {
                int i;
                int size = VTABLE_elements(interp, args);
                repl = string_copy(interp, VTABLE_get_string_keyed_int(interp, args, 0));
                for ( i=1; i<size; i++ ) {
                    repl = Parrot_sprintf_c(interp, "%Ss, %Ss", repl, VTABLE_get_string_keyed_int(interp, args, i));
                }
            }
            /* %% */
            else if (string_equal(interp, key, PERCENT)) {
                repl = PERCENT;
            }
            /* unrecognized %_ */
            else {
                position += 2;
                continue;
            }

            repl_len = string_length(interp, repl);
            string_replace(interp, format, position, 2, repl, NULL);
            position += repl_len;
            position = string_str_index(interp, format, PERCENT, position);
        }

        PMC_str_val(SELF) = string_append(interp, PMC_str_val(SELF), format);
        if (string_equal(interp, string_substr(interp, format, -1, 1, NULL, 0), NEWLINE)) {
            PMC_str_val(SELF) = string_append(interp, PMC_str_val(SELF), NEWLINE);
        }
    }

/*

=item C<unique([string fmt])>

Each call to C<unique> returns a unique number, or if a C<fmt>
parameter is given it returns a unique string beginning with
C<fmt>.  (This may eventually be generalized to allow
uniqueness anywhere in the string.)  The function starts
counting at 10 (so that the values 0..9 can be considered "safe").

=cut

*/

    PMETHOD void unique(STRING *format :optional , INTVAL has_format :opt_flag) {
        static INTVAL serno = 10;
        STRING *id;

        int current_serno =serno++;

        id = string_from_int(interp, current_serno);

        if (has_format && format != PMCNULL) {
            id = Parrot_sprintf_c(interp, "%Ss%Ss", format, id);
        }
        preturn(STRING* id);
    }

/*

=item C<escape(string str)>

   Returns an escaped value of C<str> suitable for including in PIR.
   If the string contains any non-ASCII characters, then it's
   prefixed with 'unicode:'.

=cut

*/
    METHOD STRING* escape(STRING *str) {
        STRING *SLASH_U = string_from_const_cstring(INTERP, "\\u", 0);
        STRING *SLASH_X = string_from_const_cstring(INTERP, "\\x", 0);

        str = string_escape_string(interp, str);
        str = Parrot_sprintf_c(interp, "\"%Ss\"", str);
        if (string_str_index(interp, str, SLASH_U, 0) >= 0
                || string_str_index(interp, str, SLASH_X, 0) >= 0) {
            str = string_concat(interp, string_from_const_cstring(interp, "unicode:", 0), str, 0);
        }
        return str;
    }
}



/*
=back

=head1 AUTHOR

Kevin Tew (tewky@yahoo.com is the author and maintainer of the C PMC version.
Patrick Michaud (pmichaud@pobox.com) is the author and maintainer.
Patches and suggestions should be sent to the Perl 6 compiler list
(perl6-compiler@perl.org).

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