/*
** 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<store_lex>(in STR, invar PMC)

Store object $2 as lexical symbol $1. The opcode might succeed
or throw an exception on unknown lexical names depending on the
implementation of the LexPad PMC.
Parrot's LexPad throws an exception for unknown names.


=cut

op store_lex(in STR, invar PMC) {
    parrot_context_t * const ctx = CONTEXT(interp->ctx);
    STRING * const lex_name = $1;
    PMC * const lex_pad = Parrot_find_pad(interp, lex_name, ctx);
    if (PMC_IS_NULL(lex_pad)) {
        real_exception(interp, NULL, LEX_NOT_FOUND,
                "Lexical '%Ss' not found", lex_name);
    }
    VTABLE_set_pmc_keyed_str(interp, lex_pad, lex_name, $2);
    goto NEXT();
}

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

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

Find the lexical variable named $2 and store it in $1. This
opcode either throws an exception or returns a Null PMC for the failure case,
depending on the implementation of the LexPad PMC. Parrot's
standard LexPad throws and exception for non-existing names.

=cut

op find_lex(out PMC, in STR) {
    parrot_context_t * const ctx = CONTEXT(interp->ctx);
    STRING * const lex_name = $2;
    PMC * const lex_pad = Parrot_find_pad(interp, lex_name, ctx);
    PMC *result = NULL;

    if (!PMC_IS_NULL(lex_pad))
        result = VTABLE_get_pmc_keyed_str(interp, lex_pad, lex_name);
    if (!result) {
        real_exception(interp, NULL, LEX_NOT_FOUND,
                "Lexical '%Ss' not found", lex_name);
    }
    $1 = result;
    goto NEXT();
}

=back

=cut

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

=head2 Namespace opcodes

=over 4

=item B<get_namespace>(out PMC)

Set $1 to the current namespace.

=item B<get_namespace>(out PMC, in PMC)

Set $1 to the namespace denoted by the key constant $2, relative to the
current namespace.  If the namespace doesn't exist, $1 is set to null.

=cut

op get_namespace(out PMC) {
    PMC * const cur_ns = CONTEXT(interp->ctx)->current_namespace;
    $1 = cur_ns;
    goto NEXT();
}

op get_namespace(out PMC, in PMC) {
    PMC * const cur_ns = CONTEXT(interp->ctx)->current_namespace;
    PMC *ns = Parrot_get_namespace_keyed(interp, cur_ns, $2);
    $1 = ns ? ns : PMCNULL;
    goto NEXT();
}

=item B<get_hll_namespace>(out PMC)

Set $1 to the current HLL root namespace.

=item B<get_hll_namespace>(out PMC, in PMC)

Set $1 to the namespace denoted by the key constant $2, relative to the
current HLL root namespace.  If the namespace doesn't exist, $1 is set to
null.

=cut

op get_hll_namespace(out PMC) {
    PMC * const hll_ns = Parrot_get_ctx_HLL_namespace(interp);
    $1 = hll_ns;
    goto NEXT();
}

op get_hll_namespace(out PMC, in PMC) {
    PMC * const hll_ns = Parrot_get_ctx_HLL_namespace(interp);
    PMC *ns = Parrot_get_namespace_keyed(interp, hll_ns, $2);
    $1 = ns ? ns : PMCNULL;
    goto NEXT();
}

=item B<get_root_namespace>(out PMC)

Set $1 to the true root namespace.

=item B<get_root_namespace>(out PMC, in PMC)

Set $1 to the namespace denoted by the key constant $2, relative to the true
root namespace.  If the namespace doesn't exist, $1 is set to null.

=cut

op get_root_namespace(out PMC) {
    PMC * const root_ns = interp->root_namespace;
    $1 = root_ns;
    goto NEXT();
}

op get_root_namespace(out PMC, in PMC) {
    PMC * const root_ns = interp->root_namespace;
    PMC *ns = Parrot_get_namespace_keyed(interp, root_ns, $2);
    $1 = ns ? ns : PMCNULL;
    goto NEXT();
}

=back

=cut

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

=head2 Global variable 'get' opcodes

=over 4

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

Set $1 to the global named $2 in current namespace.  If the global doesn't
exist, $1 is set to null.

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

Set $1 to the global named $3 in the namespace denoted by the key constant
$2, relative to the current namespace.  If the namespace or the global
doesn't exist, $1 is set to null.

=cut

op get_global(out PMC, in STR) {
    PMC * const cur_ns = CONTEXT(interp->ctx)->current_namespace;
    $1 = Parrot_find_global_op(interp, cur_ns, $2, expr NEXT());
    goto NEXT();
}

op get_global(out PMC, in PMC, in STR) {
    PMC * const cur_ns = CONTEXT(interp->ctx)->current_namespace;
    PMC *ns = Parrot_get_namespace_keyed(interp, cur_ns, $2);
    $1 = Parrot_find_global_op(interp, ns, $3, expr NEXT());
    goto NEXT();
}

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

Set $1 to the global named $2 in the current HLL root namespace.  If the
global doesn't exist, $1 is set to null.

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

Set $1 to the global named $3 in the namespace denoted by the key constant
$2, relative to the current HLL root namespace.  If the namespace or the
global doesn't exist, $1 is set to null.

=cut

op get_hll_global(out PMC, in STR) {
    PMC * const hll_ns = Parrot_get_ctx_HLL_namespace(interp);
    $1 = Parrot_find_global_op(interp, hll_ns, $2, expr NEXT());
    goto NEXT();
}

op get_hll_global(out PMC, in PMC, in STR) {
    PMC * const hll_ns = Parrot_get_ctx_HLL_namespace(interp);
    PMC *ns = Parrot_get_namespace_keyed(interp, hll_ns, $2);
    $1 = Parrot_find_global_op(interp, ns, $3, expr NEXT());
    goto NEXT();
}

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

Set $1 to the global named $2 in the true root namespace.  If the global
doesn't exist, $1 is set to null.

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

Set $1 to the global named $3 in the namespace denoted by the key constant
$2, relative to the true root namespace.  If the namespace or the global
doesn't exist, $1 is set to null.

=cut

op get_root_global(out PMC, in STR) {
    PMC * const root_ns = interp->root_namespace;
    $1 = Parrot_find_global_op(interp, root_ns, $2, expr NEXT());
    goto NEXT();
}

op get_root_global(out PMC, in PMC, in STR) {
    PMC * const root_ns = interp->root_namespace;
    PMC *ns = Parrot_get_namespace_keyed(interp, root_ns, $2);
    $1 = Parrot_find_global_op(interp, ns, $3, expr NEXT());
    goto NEXT();
}

=back

=cut

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

=head2 Global variable 'set' opcodes

=over 4

=item B<set_global>(in STR, invar PMC)

Set the global named $1 in the current namespace to $2.

=item B<set_global>(in PMC, in STR, invar PMC)

Set the global named $2 in the namespace denoted by the key constant $1,
relative to the current namespace, to $3.  If the namespace does not exist,
it is created.

=cut

op set_global(in STR, invar PMC) {
    PMC * const cur_ns = CONTEXT(interp->ctx)->current_namespace;
    Parrot_set_global(interp, cur_ns, $1, $2);
    goto NEXT();
}

op set_global(in PMC, in STR, invar PMC) {
    PMC * const cur_ns = CONTEXT(interp->ctx)->current_namespace;
    PMC *ns = Parrot_make_namespace_keyed(interp, cur_ns, $1);
    Parrot_set_global(interp, ns, $2, $3);
    goto NEXT();
}

=item B<set_hll_global>(in STR, invar PMC)

Set $1 to the global named $2 in the current HLL root namespace.  If the
global doesn't exist, $1 is set to null.

=item B<set_hll_global>(in PMC, in STR, invar PMC)

Set $1 to the global named $3 in the namespace denoted by the key constant
$2, relative to the current HLL root namespace.  If the namespace or the
global doesn't exist, $1 is set to null.

=cut

op set_hll_global(in STR, invar PMC) {
    PMC * const hll_ns = Parrot_get_ctx_HLL_namespace(interp);
    Parrot_set_global(interp, hll_ns, $1, $2);
    goto NEXT();
}

op set_hll_global(in PMC, in STR, invar PMC) {
    PMC * const hll_ns = Parrot_get_ctx_HLL_namespace(interp);
    PMC *ns = Parrot_make_namespace_keyed(interp, hll_ns, $1);
    Parrot_set_global(interp, ns, $2, $3);
    goto NEXT();
}

=item B<set_root_global>(in STR, invar PMC)

Set $1 to the global named $2 in the true root namespace.  If the global
doesn't exist, $1 is set to null.

=item B<set_root_global>(in PMC, in STR, invar PMC)

Set $1 to the global named $3 in the namespace denoted by the key constant
$2, relative to the true root namespace.  If the namespace or the global
doesn't exist, $1 is set to null.

=cut

op set_root_global(in STR, invar PMC) {
    PMC * const root_ns = interp->root_namespace;
    Parrot_set_global(interp, root_ns, $1, $2);
    goto NEXT();
}

op set_root_global(in PMC, in STR, invar PMC) {
    PMC * const root_ns = interp->root_namespace;
    PMC *ns = Parrot_make_namespace_keyed(interp, root_ns, $1);
    Parrot_set_global(interp, ns, $2, $3);
    goto NEXT();
}

=back

=cut

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

=head2 Deprecated global variable ops

Operations to modify global variables

=over 4

=cut

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

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

Store value $2 as global symbol $1 in the current namespace.

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

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

Store global $3 as global symbol $2 in namespace designated by $1.  If
namespace does not exist, create it.  $1 may be a key, a string, or an array
of strings.

=cut

op store_global(in STR, invar PMC) {
    Parrot_store_global_cur(interp, $1, $2);
    goto NEXT();
}

op store_global(in STR, in STR, invar PMC) {
    Parrot_store_global_s(interp, $1, $2, $3);
    goto NEXT();
}

op store_global(in PMC, in STR, invar PMC) {
    Parrot_store_global_k(interp, $1, $2, $3);
    goto NEXT();
}

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

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

Find the global named $2 in the current namespace and store it in $1.

If the global doesn't exist either throws an exception or sets $1 to the
Null PMC, depending on current errors settings. See B<errorson>.

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

Find the global named $3 in the namespace named $2 and store it in $1.

If the global doesn't exist either throws an exception or sets $1 to the
Null PMC, depending on current errors settings. See B<errorson>.

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

Find the global named $3 in the namespace designated by $2 and store it in
$1.  $2 may be a key, a string, or an array of strings.

If the global doesn't exist either throws an exception or sets $1 to the
Null PMC, depending on current errors settings.  See B<errorson>.

=cut

op find_global(out PMC, in STR) {
    PMC * const cur_ns = CONTEXT(interp->ctx)->current_namespace;
    $1 = Parrot_find_global_op(interp, cur_ns, $2, expr NEXT());
    goto NEXT();
}

op find_global(out PMC, in STR, in STR) {
    PMC * const ns = Parrot_get_namespace_keyed_str(interp,
                                                    Parrot_get_ctx_HLL_namespace(interp),
                                                    $2);
    $1 = Parrot_find_global_op(interp, ns, $3, expr NEXT());
    goto NEXT();
}

op find_global(out PMC, in PMC, in STR) {
    PMC * const ns = Parrot_get_namespace_keyed(interp,
                                                Parrot_get_ctx_HLL_namespace(interp),
                                                $2);
    $1 = Parrot_find_global_op(interp, ns, $3, expr NEXT());
    goto NEXT();
}

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

Find the name $2 in lexical, current, global, or builtin namespace and
store it in $1. If the name doesn't exist
either throws an exception or sets $1 to PMCNULL, depending on current
errors settings. See B<errorson>.

=cut

op find_name(out PMC, in STR) {
    if (!$2)
        internal_exception(1, "Tried to find null name");

    $1 = Parrot_find_name_op(interp, $2, expr NEXT());
    goto NEXT();
}

=back

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

=head1 COPYRIGHT

Copyright (C) 2001-2006, The Perl Foundation.

=head1 LICENSE

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

=cut

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