/*
** var.ops
*/

VERSION = PARROT_VERSION;

=head1 NAME

var.ops - Variable Ops

=head1 DESCRIPTION

These operations deal with both lexical and global variables,
as well as the symbol tables that contain them.

=cut

###############################################################################

=head2 Lexical variable ops

Operations to create, modify and delete lexical variables.

=over 4

=cut

########################################

=item B<new_pad>(in INT)

Create a new lexical scope pad with static nesting depth $1
and push it onto the lexical scope stack. Static depths 0
through $1 - 1, inclusive, are copied from the current static
nesting.

=item B<new_pad>(out PMC, in INT)

Create a new lexical scope pad with static nesting depth $2
and store it in $1 (do NOT push on the stack). Static depths 0
through $2 - 1, inclusive, are copied from the current static
nesting.

=cut

op new_pad(in INT) {
    PMC * pad;
    PMC * parent = scratchpad_get_current(interpreter);
    pad = scratchpad_new(interpreter, parent, $1);
    stack_push(interpreter, &interpreter->ctx.pad_stack, pad,
               STACK_ENTRY_PMC, STACK_CLEANUP_NULL);
    goto NEXT();
}

op new_pad(out PMC, in INT) {
    PMC * parent = scratchpad_get_current(interpreter);
    $1 = scratchpad_new(interpreter, parent, $2);
    goto NEXT();
}

########################################

=item B<push_pad>(in PMC)

Push the scratchpad in $1 onto the lexical scope stack.

=cut

op push_pad(in PMC) {
    stack_push(interpreter, &interpreter->ctx.pad_stack, $1,
               STACK_ENTRY_PMC, STACK_CLEANUP_NULL);
    goto NEXT();
}

########################################

=item B<pop_pad>()

Pop the current lexical scope pad off the stack

=item B<pop_pad>(out PMC)

Pop the current lexical scope pad off the stack and store
it in $1 (XXX JPS: not implemented yet).

=cut

op pop_pad() {
    stack_pop(interpreter, &interpreter->ctx.pad_stack,
              NULL, STACK_ENTRY_PMC);
    goto NEXT();
}

########################################

=item B<peek_pad>(out PMC)

Store the current lexical scope pad (i.e. the one at the
top of the lexical pad stack) in $1.

=cut

op peek_pad(out PMC) {
    $1 = scratchpad_get_current(interpreter);
    goto NEXT();
}

########################################

=item B<store_lex>(in STR, in PMC)

Store object $2 as lexical symbol $1.  $1 must have already been
created at some static depth.

=item B<store_lex>(in INT, in STR, in PMC)

Store object $3 as lexical $2 at depth $1.  If [$1, $2] does not
exist, it will be created.  If $1 is negative, count out from the
current lexical scope; otherwise, count in from the outermost scope.
So store_lex -1, .... will operate on the current pad.

=item B<store_lex>(in INT, in INT, in PMC)

Store object $3 at lexical position $2 at depth $1.  If [$1, $2] does
not exist, it will be created.  If $1 is negative, count out from the
current lexical scope; otherwise, count in from the outermost scope.
So store_lex -1, .... will operate on the current pad.

=cut

op store_lex(in STR, in PMC) {
    PMC * pad = scratchpad_get_current(interpreter);
    scratchpad_store(interpreter, pad, $1, 0, $2);
    goto NEXT();
}

op store_lex(in INT, in STR, in PMC) {
    PMC * pad = scratchpad_get_current(interpreter);
    scratchpad_store_index(interpreter, pad, $1, $2, 0, $3);
    goto NEXT();
}

op store_lex(in INT, in INT, in PMC) {
    PMC * pad = scratchpad_get_current(interpreter);
    scratchpad_store_index(interpreter, pad, $1, NULL, $2, $3);
    goto NEXT();
}

########################################

=item B<find_lex>(out PMC, in STR)

Find the lexical variable named $2 (at any depth) and store it in $1.

=item B<find_lex>(out PMC, in INT, in STR)

Find the lexical variable named $3 at depth $2 and store it in $1.
If $2 is negative the, count out from the current lexical scope;
otherwise, count up from the outermost scope.

=item B<find_lex>(out PMC, in INT, in INT)

Find the lexical variable at position $3 at depth $2 and store it in
$1. If $2 is negative the, count out from the current lexical scope;
otherwise, count up from the outermost scope.

=cut

op find_lex(out PMC, in STR) {
    opcode_t * resume;
    if (!$2)
        internal_exception(1, "Tried to get null lexical.");
    $1 = scratchpad_get(interpreter, scratchpad_get_current(interpreter), $2, 0);
    resume = expr NEXT();
    if (!$1)
        real_exception(interpreter, resume, LEX_NOT_FOUND,
            "Lexical '%s' not found", string_to_cstring(interpreter, $2));
    restart ADDRESS(resume);
}

op find_lex(out PMC, in INT) {
    PMC * pad = scratchpad_get_current(interpreter);
    PMC * lex = $1 = scratchpad_get(interpreter, pad, NULL, $2);
    opcode_t *resume = expr NEXT();
    if (!lex)
        real_exception(interpreter, resume, LEX_NOT_FOUND,
            "Lexical #'%d' not found", (int) $2);
    restart ADDRESS(resume);
}

op find_lex(out PMC, in INT, in STR) {
    opcode_t * resume;
    if (!$3)
        internal_exception(1, "Tried to get null lexical.");
    $1 = scratchpad_get_index(interpreter, scratchpad_get_current(interpreter),
                              $2, $3, 0);
    resume = expr NEXT();
    if (!$1)
        real_exception(interpreter, resume, LEX_NOT_FOUND,
            "Lexical '%s' not found", string_to_cstring(interpreter, $3));
    restart ADDRESS(resume);
}

op find_lex(out PMC, in INT, in INT) {
    PMC * pad = scratchpad_get_current(interpreter);
    PMC *lex = $1 = scratchpad_get_index(interpreter, pad, $2, NULL, $3);
    opcode_t *resume = expr NEXT();
    if (!lex)
        real_exception(interpreter, resume, LEX_NOT_FOUND,
            "Lexical #'%d' not found", (int) $3);
    restart ADDRESS(resume);
}

=back

=cut

###############################################################################

=head2 Global variable ops

Operations to modify global variables

=over 4

=cut

########################################

=item B<store_global>(in STR, in PMC)

Store global $2 as global symbol $1

=cut

op store_global(in STR, in PMC) {
    PMC * key = key_new_string(interpreter, $1);
    PMC * globals = interpreter->perl_stash->stash_hash;
    globals->vtable->set_pmc_keyed(interpreter, globals, key, $2);
    goto NEXT();
}

########################################

=item B<find_global>(out PMC, in STR)

Find the global named $2 and store it in $1

=cut

op find_global(out PMC, in STR) {
    opcode_t * resume;
    PMC* key = key_new_string(interpreter, $2);
    if (!$2)
        internal_exception(1, "Tried to get null global.");
    
    resume = expr NEXT();
    if (!VTABLE_exists_keyed(interpreter,
                       interpreter->perl_stash->stash_hash, key)) 
        real_exception(interpreter, resume, GLOBAL_NOT_FOUND,
                "Global '%s' not found\n", string_to_cstring(interpreter, $2));
                       
    $1 = VTABLE_get_pmc_keyed(interpreter,
				interpreter->perl_stash->stash_hash, key);

    restart ADDRESS(resume);
}

=back

=cut

###############################################################################

=head1 COPYRIGHT

Copyright (C) 2001-2003 The Perl Foundation.  All rights reserved.

=head1 LICENSE

This program is free software. It is subject to the same license
as the Parrot interpreter itself.

=cut
