/****************************************************************************
**
*W  vars.h                      GAP source                   Martin Schönert
**
**
*Y  Copyright (C)  1996,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
*Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
*Y  Copyright (C) 2002 The GAP Group
**
**  This file declares the functions of variables package.
**
**  The variables  package is  the  part of   the interpreter  that  executes
**  assignments to variables and evaluates references to variables.
**
**  There are five  kinds of variables,  local variables (i.e., arguments and
**  locals), higher variables (i.e., local variables of enclosing functions),
**  global variables, list elements, and record elements.
*/

#ifndef libGAP_GAP_VARS_H
#define libGAP_GAP_VARS_H


/****************************************************************************
**
*S  T_LVARS . . . . . . . . . . . . . . . .  symbolic name for lvars bag type
**
**  'T_LVARS' is the type of bags used to store values of local variables.

#define T_LVARS                 174
*/

/****************************************************************************
**
*V  CurrLVars   . . . . . . . . . . . . . . . . . . . . . local variables bag
**
**  'CurrLVars'  is the bag containing the  values  of the local variables of
**  the currently executing interpreted function.
**
**  Assignments  to  the local variables change   this bag.  We  do  not call
**  'CHANGED_BAG' for  each of such change.  Instead we wait until  a garbage
**  collection begins  and then  call  'CHANGED_BAG'  in  'BeginCollectBags'.
*/
extern  libGAP_Bag             libGAP_CurrLVars;






/****************************************************************************
**
*V  BottomLVars . . . . . . . . . . . . . . . . .  bottom local variables bag
**
**  'BottomLVars' is the local variables bag at the bottom of the call stack.
**  Without   such a dummy  frame at  the bottom, 'SWITCH_TO_NEW_LVARS' would
**  have to check for the bottom, slowing it down.
**
*/
extern  libGAP_Bag             libGAP_BottomLVars;


/****************************************************************************
**
*V  PtrLVars  . . . . . . . . . . . . . . . .  pointer to local variables bag
**
**  'PtrLVars' is a pointer to the 'CurrLVars' bag.  This  makes it faster to
**  access local variables.
**
**  Since   a   garbage collection may  move   this  bag  around, the pointer
**  'PtrLVars' must be recalculated afterwards in 'VarsAfterCollectBags'.
*/
extern  libGAP_Obj *           libGAP_PtrLVars;


/****************************************************************************
**
*F  CURR_FUNC . . . . . . . . . . . . . . . . . . . . . . .  current function
**
**  'CURR_FUNC' is the function that is currently executing.
**
**  This  is  in this package,  because  it is stored   along  with the local
**  variables in the local variables bag.
*/
#define libGAP_CURR_FUNC       (libGAP_PtrLVars[0])


/****************************************************************************
**
*F  BRK_CALL_TO() . . . . . . . . . expr. which was called from current frame
*F  SET_BRK_CALL_TO(expr) . . . set expr. which was called from current frame
*/

#ifdef TRACEFRAMES

extern libGAP_Obj libGAP_STEVES_TRACING;
extern libGAP_Obj libGAP_True;
#include <stdio.h>

static inline void libGAP_SetBrkCallTo( libGAP_Expr expr, char * libGAP_file, int line ) {
  if (libGAP_STEVES_TRACING == libGAP_True) {
    fprintf(stderr,"SBCT: %i %x %s %i\n",
            (int)expr, (int)libGAP_CurrLVars, libGAP_file, line);
  }
  (libGAP_PtrLVars[1] = (libGAP_Obj)(libGAP_Int)(expr));
}

#else
#define libGAP_SetBrkCallTo(expr, libGAP_file, line)  (libGAP_PtrLVars[1] = (libGAP_Obj)(libGAP_Int)(expr))
#endif

#ifndef NO_BRK_CALLS
#define libGAP_BRK_CALL_TO()                   ((libGAP_Expr)(libGAP_Int)(libGAP_PtrLVars[1]))
#define libGAP_SET_BRK_CALL_TO(expr)           libGAP_SetBrkCallTo(expr, __FILE__, __LINE__)
#endif
#ifdef  NO_BRK_CALLS
#define libGAP_BRK_CALL_TO()                   /* do nothing */
#define libGAP_SET_BRK_CALL_TO(expr)           /* do nothing */
#endif


/****************************************************************************
**
*F  BRK_CALL_FROM() . . . . . . . . .  frame from which this frame was called
*F  SET_BRK_CALL_FROM(lvars)  . .  set frame from which this frame was called
*/
#ifndef NO_BRK_CALLS
#define libGAP_BRK_CALL_FROM()                 (libGAP_PtrLVars[2])
#define libGAP_SET_BRK_CALL_FROM(lvars)        (libGAP_PtrLVars[2] = (lvars))
#endif
#ifdef  NO_BRK_CALLS
#define libGAP_BRK_CALL_FROM()                 /* do nothing */
#define libGAP_SET_BRK_CALL_FROM(lvars)        /* do nothing */
#endif


/****************************************************************************
**
*F  SWITCH_TO_NEW_LVARS( <func>, <narg>, <nloc>, <old> )  . . . . . new local
**
**  'SWITCH_TO_NEW_LVARS'  creates and switches  to a new local variabes bag,
**  for  the function    <func>,   with <narg> arguments    and  <nloc> local
**  variables.  The old local variables bag is saved in <old>.
*/

extern libGAP_Obj libGAP_STEVES_TRACING;
extern libGAP_Obj libGAP_True;

#include <stdio.h>

static inline libGAP_Obj libGAP_SwitchToNewLvars(libGAP_Obj func, libGAP_UInt narg, libGAP_UInt nloc
#ifdef TRACEFRAMES
, char * libGAP_file, int line
#endif
)
{
  libGAP_Obj old = libGAP_CurrLVars;
  libGAP_CHANGED_BAG( old );
  libGAP_CurrLVars = libGAP_NewBag( libGAP_T_LVARS,
                      sizeof(libGAP_Obj)*(3+narg+nloc) );
  libGAP_PtrLVars  = libGAP_PTR_BAG( libGAP_CurrLVars );
  libGAP_CURR_FUNC = func;
  libGAP_PtrBody = (libGAP_Stat*)libGAP_PTR_BAG(libGAP_BODY_FUNC(libGAP_CURR_FUNC));
  libGAP_SET_BRK_CALL_FROM( old );
#ifdef TRACEFRAMES
  if (libGAP_STEVES_TRACING == libGAP_True) {
    libGAP_Obj n = libGAP_NAME_FUNC(func);
    libGAP_Char *s = ((libGAP_UInt)n) ? (libGAP_Char *)libGAP_CHARS_STRING(n) : (libGAP_Char *)"nameless";
    fprintf(stderr,"STNL: %s %i\n   func %lx narg %i nloc %i function name %s\n     old lvars %lx new lvars %lx\n",
            libGAP_file, line, (libGAP_UInt) func, (int)narg, (int)nloc,s,(libGAP_UInt)old, (libGAP_UInt)libGAP_CurrLVars);
  }
#endif
  return old;
}

#ifdef TRACEFRAMES
#define libGAP_SWITCH_TO_NEW_LVARS(func, narg, nloc, old)     (old) = libGAP_SwitchToNewLvars((func), (narg), (nloc), __FILE__, __LINE__)
#else
#define libGAP_SWITCH_TO_NEW_LVARS(func, narg, nloc, old)     (old) = libGAP_SwitchToNewLvars((func), (narg), (nloc))
#endif


/****************************************************************************
**
*F  SWITCH_TO_OLD_LVARS( <old> )  . . .  switch to an old local variables bag
**
**  'SWITCH_TO_OLD_LVARS' switches back to the old local variables bag <old>.
*/

static inline void libGAP_SwitchToOldLVars( libGAP_Obj old
#ifdef TRACEFRAMES
, char *libGAP_file, int line
#endif
)
{
#ifdef TRACEFRAMES
  if (libGAP_STEVES_TRACING == libGAP_True) {
    fprintf(stderr,"STOL:  %s %i old lvars %lx new lvars %lx\n",
           libGAP_file, line, (libGAP_UInt)libGAP_CurrLVars,(libGAP_UInt)old);
  }
#endif
  libGAP_CHANGED_BAG( libGAP_CurrLVars );
  libGAP_CurrLVars = (old);
  libGAP_PtrLVars  = libGAP_PTR_BAG( libGAP_CurrLVars );
  libGAP_PtrBody = (libGAP_Stat*)libGAP_PTR_BAG(libGAP_BODY_FUNC(libGAP_CURR_FUNC));
}

#ifdef TRACEFRAMES
#define libGAP_SWITCH_TO_OLD_LVARS(old) libGAP_SwitchToOldLVars((old), __FILE__,__LINE__)
#else
#define libGAP_SWITCH_TO_OLD_LVARS(old) libGAP_SwitchToOldLVars((old))
#endif


/****************************************************************************
**
*F  ASS_LVAR( <lvar>, <val> ) . . . . . . . . . . .  assign to local variable
**
**  'ASS_LVAR' assigns the value <val> to the local variable <lvar>.
*/
#define libGAP_ASS_LVAR(lvar,val)      (libGAP_PtrLVars[(lvar)+2] = (val))


/****************************************************************************
**
*F  OBJ_LVAR( <lvar> )  . . . . . . . . . . . . . . . value of local variable
**
**  'OBJ_LVAR' returns the value of the local variable <lvar>.
*/
#define libGAP_OBJ_LVAR(lvar)          (libGAP_PtrLVars[(lvar)+2])


/****************************************************************************
**
*F  NAME_LVAR( <lvar> ) . . . . . . . . . . . . . . .  name of local variable
**
**  'NAME_LVAR' returns the name of the local variable <lvar> as a C string.
*/
#define libGAP_NAME_LVAR(lvar)         libGAP_NAMI_FUNC( libGAP_CURR_FUNC, lvar )


/****************************************************************************
**
*F  ObjLVar(<lvar>) . . . . . . . . . . . . . . . . value of a local variable
**
**  'ObjLVar' returns the value of the local variable <lvar>.
*/
extern  libGAP_Obj             libGAP_ObjLVar (
            libGAP_UInt                lvar );


/****************************************************************************
**
*F  ASS_HVAR(<hvar>,<val>)  . . . . . . . . . . . assign to a higher variable
*F  OBJ_HVAR(<hvar>)  . . . . . . . . . . . . . .  value of a higher variable
*F  NAME_HVAR(<hvar>) . . . . . . . . . . . . . . . name of a higher variable
**
**  'ASS_HVAR' assigns the value <val> to the higher variable <hvar>.
**
**  'OBJ_HVAR' returns the value of the higher variable <hvar>.
**
**  'NAME_HVAR' returns the name of the higher variable <hvar> as a C string.
*/
extern  void            libGAP_ASS_HVAR (
            libGAP_UInt                hvar,
            libGAP_Obj                 val );

extern  libGAP_Obj             libGAP_OBJ_HVAR (
            libGAP_UInt                hvar );

extern  libGAP_Char *          libGAP_NAME_HVAR (
            libGAP_UInt                hvar );


/****************************************************************************
**

*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
*/


/****************************************************************************
**

*F  InitInfoVars()  . . . . . . . . . . . . . . . . . table of init functions
*/
libGAP_StructInitInfo * libGAP_InitInfoVars ( void );


#endif // GAP_VARS_H

/****************************************************************************
**

*E  vars.c  . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
*/
