/*
** debug.ops
*/

VERSION = PARROT_VERSION;

=head1 NAME

debug.ops

=cut

=head1 DESCRIPTION

Parrot debugger

=cut

=head1 HISTORY

Initial version by Daniel Grunblatt on 2002.5.19

=cut

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

=head2 Parrot debug operations

=over 4

=cut

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

=item B<debug_init>()

Init the Parrot debugger, must be called before any other debug op.

=cut

op debug_init() :base_debug {
    PDB_t *pdb;

    if (!(interp->pdb)) {
        pdb = (PDB_t *)mem_sys_allocate_zeroed(sizeof (PDB_t));

        interp->pdb = pdb;
        pdb->cur_opcode = interp->code->base.data;
        pdb->state |= PDB_RUNNING;
    }

    goto NEXT();
}

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

=item B<debug_load>(inconst STR)

Load a Parrot source file for the current program.

=cut

op debug_load(inconst STR) :base_debug {
    const char *f;

    if (!(interp->pdb->state & PDB_BREAK)) {
        f = string_to_cstring(interp,($1));
        PDB_load_source(interp,f);
    }

    goto NEXT();
}

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

=item B<debug_break>()

Break execution and drop into the debugger.
If we are already into the debugger and is the first time we are
called set a breakpoint.

When you re run/continue the program begin debugged it will pay
no attention to the debug ops.

TODO: clone the interpreter to allow people to play into the
debugger and then continue the normal execution of the program.

=cut

op debug_break() :base_debug {
    const char *command;

    if (!(interp->pdb->state & PDB_BREAK)) {
        interp->pdb->state |= PDB_BREAK;
        interp->pdb->state |= PDB_STOPPED;
        interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
        PDB_set_break(interp,NULL);
        while (!(interp->pdb->state & PDB_EXIT)) {
            PDB_get_command(interp);
            command = interp->pdb->cur_command;
            PDB_run_command(interp,command);
        }
        /* FIXME this is not ok */
        exit(0);
    }
    interp->pdb->cur_opcode = (opcode_t *)cur_opcode + 1;
    PDB_set_break(interp,NULL);

    goto NEXT();
}

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

=item B<debug_print>()

Print all the Parrot registers at once.

=cut

op debug_print() :base_debug {
    if (!(interp->pdb->state & PDB_BREAK)) {
#if 1
        PIO_eprintf(interp, "debug_print is disabled\n");
#else
        /*
         * XXX adjust register layout
         */
        PDB_print_int(interp, &interp->int_reg, -1);
        PDB_print_num(interp, &interp->num_reg, -1);
        PDB_print_string(interp,&interp->string_reg, -1);
        PDB_print_pmc(interp,&interp->pmc_reg, -1, NULL);
#endif
    }
    goto NEXT();
}

=item B<backtrace>()

Print a backtrace.

=cut

op backtrace() :base_debug {
    PDB_backtrace(interp);
    goto NEXT();
}

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

=item B<getline>(out INT)

Get the current line number.

=cut

inline op getline(out INT) {
  struct Parrot_Context_info info;
  Parrot_Context_info(interp, CONTEXT(interp->ctx), &info);
  $1 = info.line;
  goto NEXT();
}

=item B<getfile>(out STR)

Get the name of the current file.

=cut

inline op getfile(out STR) {
  struct Parrot_Context_info info;
  Parrot_Context_info(interp, CONTEXT(interp->ctx), &info);
  $1 = string_from_cstring(interp, info.file, 0);
  goto NEXT();
}

=back

=cut

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