/*
Copyright (C) 2008-2010, Parrot Foundation.
$Id: lexinfo.pmc 47863 2010-06-26 12:50:08Z whiteknight $

=head1 NAME

src/pmc/lexinfo.pmc - LexInfo PMC

=head1 DESCRIPTION

These are the vtable functions for the lexinfo PMC.

=head2 Functions

=over 4

=cut

*/

#include "pmc/pmc_hash.h"

/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */

/*
 * LexInfo contains a constant Hash with constant string
 * keys and integer indices
 */

pmclass LexInfo extends Hash  provides hash no_ro auto_attrs {

/*

=item C<void class_init()>

Manipulate vtable->flags so that constant PMCs are created.
If your inherited LexInfo is not so constant, then don't
do that and provide a mark() method and set the custom_mark flag.

=item C<init_pmc(PMC *sub)>

Initialize the LexInfo PMC and remember the associate
subroutine.

=cut

*/

    void class_init() {

        /* there is no pmclass const_pmc flag yet */
        INTERP->vtables[entry]->flags |= VTABLE_IS_CONST_PMC_FLAG;

    }

    VTABLE void init() {
        Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "Cannot create a LexInfo PMC without an initializer");
    }

    VTABLE void init_pmc(PMC *sub) {
        PARROT_ASSERT(PObj_constant_TEST(SELF));

        /* Set value type to INTVAL */
        SELF.init_int((INTVAL)enum_type_INTVAL);
        PObj_custom_mark_destroy_SETALL(SELF);
    }

/*

=item C<void declare_lex_preg(STRING *name, INTVAL preg)>

Declare a lexical variable that is an alias for a PMC register.  The PIR
compiler calls this method in response to a ".lex STRING, PREG" directive.

=cut

*/

    METHOD declare_lex_preg(STRING *name, INTVAL preg) {
        VTABLE_set_integer_keyed_str(INTERP, SELF, name, preg);
    }


/*

=item C<PMC *inspect_str(STRING *what)>

Introspects this LexInfo structure. The only valid introspection key is
C<symbols>, which gets an array of the names of the symbols in this lexpad.

=cut

*/

    VTABLE PMC *inspect_str(STRING *what) {
        if (Parrot_str_equal(INTERP, what, CONST_STRING(INTERP, "symbols"))) {
            PMC * const result    = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray);
            const Hash *hash      = (Hash *)SELF.get_pointer();
            const UINTVAL entries = hash->entries;

            UINTVAL found   = 0;
            INTVAL  i;

            for (i = hash->mask; i >= 0; --i) {
                HashBucket *bucket = hash->bucket_indices[i];
                while (bucket) {
                    if (++found > entries)
                        Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
                            "Detected corruption at LexInfo hash %p entries %d",
                            hash, (int)entries);

                    PARROT_ASSERT(bucket->key);
                    VTABLE_push_string(INTERP, result, (STRING *)bucket->key);

                    bucket = bucket->next;
                }
            }

            return result;
        }
        else
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "Unknown introspection value '%S'", what);
    }

/*

=item C<void visit(PMC *info)>

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

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

Freeze/thaw interface used during freeze/thaw of the Sub PMC.
The implementation of the Hash PMC is called.

=cut

*/


    VTABLE void thaw(PMC *info) {
        const INTVAL elems  = VTABLE_shift_integer(INTERP, info);
        const INTVAL k_type = VTABLE_shift_integer(INTERP, info);
        const INTVAL v_type = VTABLE_shift_integer(INTERP, info);
        Hash        *hash;

        UNUSED(k_type);
        UNUSED(v_type);

        PARROT_ASSERT(v_type == enum_hash_int);
        /* TODO make a better interface for hash creation
         * TODO create hash with needed types in the first place
         */

        SELF.init_pmc(NULL);
        hash          = (Hash *)SELF.get_pointer();
        hash->entries = elems;
    }
}


/*

=back

=head1 SEE ALSO

F<docs/pdds/pdd20_lexical_vars.pod>, F<src/classes/lexpad.pmc>.

=cut

*/

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