/*
 *  debug.sli
 *
 *  This file is part of NEST.
 *
 *  Copyright (C) 2004 The NEST Initiative
 *
 *  NEST is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  NEST is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

% Debuggin support for SLI
/*
BeginDocumentation
   
   Name: debug.sli - Debugging support for sli 
   
   Synopsis: 
     (debug) run

   Description: 
     Defines operators which support debugging. All auxiliary operators
     are defined in the dictionary debugdict.

   Author: 
    Marc-Oliver Gewaltig, Honda R&D

   FirstVersion: 
    July 9 1999

   SeeAlso: inspect

*/


systemdict begin

%% Resume operation after a system signal
/*
BeginDocumentation
   
   Name: resume - Resume interrupted SLI program after a system signal.
   
   Synopsis: resume

   Description: 
     resume tries to restore the state of the interpreter stacks to
     their state immediately before the signal.

     The following stacks are restored in this order:
     1. operand stack from    errordict /ostack
     2. dictionary stack from errordict /ostack
     3. execution stack from errordict  /estack

   Author: 
    Marc-Oliver Gewaltig, Honda R&D

   FirstVersion: 
    Sept. 10 1999

   SeeAlso: raiseerror

*/

/resume
{
  errordict dup /errorname known
  {
    /errorname get 
    /SystemSignal eq
    {
      errordict /errorname undef %% clear error state
      errordict /ostack get      %% Restore operand stack
      restoreostack
      errordict /dstack get      %% Restore dictionary stack
      restoredstack
      errordict /estack get      %% Restore execution stack
      restoreestack              %% Note that this operation does not return!
    }
    { 
      errordict /dstack get      %% Restore dictionary stack
      restoredstack      
      %(Resume only possible after /SignalError) 100 message
    } ifelse
  } 
  { 
    pop
    (Resume only possible after /SignalError) 100 message
  } ifelse
} def

 /debugdict 
 <<
   /SingleStepMode false
 >> def

/*
BeginDocumentation
   
   Name: inspect - inspect an object
   
   Synopsis: any inspect -> -
             any  ?      -> -

   Description: 
     inspect (or ?) displays the contents of an object in a formatted form.
     SLI procedures are displayed with indentation according to their 
     nesting level. The amount of indentation is controlled by the
     value of :INDENTATION, which is defined in debugdir.

     The most common usage is to apply inspect to a literal. Inspect
     resolves the name in the current dictionary context and gives
     a formatted output of the contents.

     Numeric values are displayed with the letters (d) or (i) to indicate
     the type of the numeral.

     The display of arrays is truncated, if they are longer than the
     value of :ARRAYLIMIT. the remaining entries are replaced by
     an elipsis ( ... ).

   Examples:

    /stack inspect

    /stack : proceduretype := 
    {
      0i
      1i
      -count-
      3i
      -sub_ii-
      {
        -index-
        =
      }
      -for-
    }

    SLI ] [10] Range inspect
    [ 1i 2i 3i 4i 5i   ...  ]

    SLI ] [1. 10.] Range inspect
    [ 1d 2d 3d 4d 5d   ...  ]

    
   Bugs: 
     The displays of TypeTrees and Procedures could be more elaborated.
     Maybe the next version will show the individual parameter-lists of
     a TypeTree.

   Author: 
     Marc-Oliver Gewaltig, Honda R&D

   FirstVersion: 
     July 9 1999

   Remarks: 
    ? can be used as shortcut to inspect

   SeeAlso: 

*/

 /inspect
 {
   debugdict begin
   inspect
   end
 } bind def

/? /inspect load def

end

debugdict begin

/bdef {bind def} bind def

/:INDENTATION   2 def
/:INDENTCOUNT   0 def
/:ARRAYLIMIT    5 def
/:FILLCHAR      ( ) def

% ostream tab
/tab
{
  :INDENTCOUNT
  {
    :FILLCHAR <- 
  } repeat
} bdef

/lf
{
  (\n) <-
} bdef

/moreindent
{
  /:INDENTCOUNT dup load :INDENTATION add def
} def

/lessindent
{
  /:INDENTCOUNT dup load :INDENTATION sub def
} def


% ostream proc inspect
/:pr_p
{
  exch % proc ostream
  ({) <- endl
  moreindent
  exch  % ostream proc
  cvlit % ostream array
  {
    % ostream item
    exch tab exch pr endl
  } forall
  lessindent
  tab (}) <-
} def

% ostream litproc pprint
/:pr_lp
{
  exec :pr_p
} def

% ostream array 
/:pr_a
{
  size 0 eq
  { <-- }
  {
    dup 3 -1 roll
    tab ([ ) <- exch
    0 :ARRAYLIMIT getinterval
    {
      pr ( ) <-
    } forall
    exch length :ARRAYLIMIT gt
    {
      (  ...  ) <-
    } if
    (]) <-
  } ifelse
} bdef
 
/:pr_d
{
  exch showpoint exch <- noshowpoint
} def

/:pr_i
{
   <-
} def

/:pr_t
{
  % stream trie -> stream
  1 index exch trieinfo
} def

/:pr_any /<-- load def

/:pr trie
 [/ostreamtype /anytype]              /:pr_any load addtotrie
 [/ostreamtype /proceduretype]        /:pr_p   load addtotrie
 [/ostreamtype /arraytype]            /:pr_a   load addtotrie
 [/ostreamtype /literalproceduretype] /:pr_lp  load addtotrie
 [/ostreamtype /doubletype]           /:pr_d   load addtotrie
 [/ostreamtype /integertype]          /:pr_i   load addtotrie
 [/ostreamtype /trietype]             /:pr_t   load addtotrie
def

/pr_any
{
  :pr
} def


/pr trie
 [/ostreamtype /anytype]  /pr_any load addtotrie
def

/inspect_any
{ 
 debugdict begin
  cout exch pr endl ;
 end
} def

/inspect_l
{ 
 debugdict begin
  dup  cout exch % /lit ostream /lit
  <-- ( : ) <- 1 index lookup
  {
    type <- ( := ) <- lf
    exch load 
    pr endl ;
  }
  {
    (undefined) <- endl 2 npop
  } ifelse
 end
} def

/inspect trie
[/anytype] /inspect_any load addtotrie
[/literaltype] /inspect_l load addtotrie
def

/?
{
  inspect
} bdef
end


/* BeginDocumentation
Name: break - interrupt the execution of a procedure for inspection
SeeAlso: continue
*/

/debugprompt
{
  (break mode ) 
  count 1 gt_ii      % counter has to be corrected for operative
  {                  % objects on the stack
    ([) join_s
    count 1 sub_ii cvs join_s
  } if
  (] ) join_s
} bind def

/break
{		
 {
  {
    debugprompt GNUreadline
    {
      cst cvx_a stopped {handleerror} if
    } if
  } stopped {handleerror} if % to catch signals
 } loop
} bind def

/* BeginDocumentation
Name: continue - continue an interrupted  procedure
SeeAlso: break
*/

/continue /exit load def