/* libsizzle/eval.h - evaluator
 
  Copyright (C) 1999, 2000 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
 
  This 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, or (at your option)
  any later version.
  
  This software 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 this package; see the file COPYING.  If not, write to the
  Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  MA 02111-1307, USA.  */

#ifndef __SIZZLE_EVAL_H__
#define __SIZZLE_EVAL_H__

#if HAVE_CONFIG_H
# include <config.h>
#endif 

#if __SIZZLE_IMPORT__
# define SIZZLE_API __declspec (dllimport)
#elif __SIZZLE_EXPORT__ 
# define SIZZLE_API __declspec (dllexport)
#else
# define SIZZLE_API
#endif

#include "node.h"
#include "sig.h"
#include "nls.h"

/* Convenience macros for parameter handling.  */

/* Store the next parameter (taken from the implicit variable
   @var{param}, which must be in the current scope) into @var{value}
   and advance @var{param} to the next list member.  An error will be
   returned from the current function on error.  */
#define NEXT_ARG(value)							   \
  do									   \
    {									   \
      if (!param)							   \
        {								   \
          *result = zzz_make_wna_exception				   \
            (zzz_make_list 						   \
	     (zzz_make_string (zzz_too_few_arguments, -1),		   \
	      zzz_make_string (s_func_name, -1),	   		   \
	      zzz_make_string ("'", -1), 				   \
	      NULL));							   \
	  return RESULT_EXCEPTION;					   \
	}								   \
      value = car (param);						   \
      param = cdr (param);						   \
    }									   \
  while (0)

/* Returns an error from the current function if any parameters are
   left in the explicit list variable @var{param}.  */
#define LAST_ARG()							\
  do									\
    {									\
      if (param)							\
        {								\
	  *result = zzz_make_wna_exception				\
            (zzz_make_list						\
	     (zzz_make_string (zzz_too_many_arguments, -1),		\
	      zzz_make_string (s_func_name, -1),			\
	      zzz_make_string ("'", -1),				\
	      NULL));							\
	  return RESULT_EXCEPTION;					\
	}								\
    }									\
  while (0)

/* Check whether any signals have been caught and invokes the Scheme
   signal handlers in that case.  Also checks for SIGINT, and returns
   an interrupt object from the current function if interrupted.  This
   macro should be called from all loops which might take a while, so
   that they can be interrupted with C-c.  */
#define ZZZ_TICK() 							  \
  do {									  \
    result_t zzz_tick_err;						  \
    zzz_scm_t zzz_tick_res;						  \
    if (zzz_interrupt_requested)					  \
      return RESULT_INTERRUPT;						  \
    if (zzz_signal_count)						  \
      {									  \
	if ((zzz_tick_err = zzz_internal_handle_signals (&zzz_tick_res))  \
	    != RESULT_SUCCESS) 						  \
	  {								  \
	    *result = zzz_tick_res;					  \
	    return zzz_tick_err;					  \
	  }								  \
      }									  \
  } while (0)

/* Wraps the system call @var{call} in a loop catching @code{EINTR}
   errors, and stores the result of the call in @var{result}.  Also
   calls ZZZ_TICK() in the waiting loop.  */
#define ZZZ_SYSCALL(result, call)		\
  do {						\
      int __res;				\
      do {					\
	ZZZ_TICK();				\
	__res = call;				\
      } while (__res == -1 && errno == EINTR);	\
      result = __res;				\
  } while (0)

/* This variable is used by the signal checking macros above.  Not for
   application use.  */
SIZZLE_API extern int zzz_interrupt_requested;

/* Customization variables.  They are bound to Scheme names and can be
   read from the Scheme level.  Some can be modified also, refer to
   the reference manual to see what they are doing.  */

/* Variable `%eval-time-taken%'.  */
SIZZLE_API extern int zzz_eval_time_taken;
/* Variable `%print-read%'.  */
SIZZLE_API extern int zzz_eval_print_read;
/* Variable `%print-result%'.  */
SIZZLE_API extern int zzz_eval_print_result;
/* Variable `%save-backtrace%'.  */
SIZZLE_API extern int zzz_eval_save_backtrace;
/* Variable `%print-backtrace-limit%'.  */
SIZZLE_API extern int zzz_eval_print_backtrace_limit;

/* When calling this function, @var{expr} must be a pair.  If the car
   of @var{expr} is a symbol, and refers to a bound local or global
   variable or constant, it will be replaced with a more efficient
   object, such as an lloc, gloc or constant value.  */
SIZZLE_API void zzz_memoize_car (zzz_scm_t env, zzz_scm_t expr);

/* Applies the procedure @var{proc} to the parameters listed in
  @var{param_list}.  The caller must ensure that @var{param_list} is a
  valid list before calling this function. Application takes place in
  the dynamic environment @var{env}. On success, returns
  @code{RESULT_SUCCESS} and stores the result of the application in
  the location pointed to by @var{result}, returns an error code on
  error, with an error object stored in the location pointed to by
  @var{result}.  */
SIZZLE_API result_t zzz_apply (zzz_scm_t env, zzz_scm_t proc,
			       zzz_scm_t param_list, zzz_scm_t * result);

/* Evaluates the given expression @var{expr} and stores the result in
  the location pointed to by @var{result}. Evaluation takes place in
  environment @var{env}. On success, returns @code{RESULT_SUCCESS} and
  returns an error code otherwise, with an appropriate error object
  stored in the location pointed to by @var{result}.  */
SIZZLE_API result_t zzz_evaluate (zzz_scm_t env, zzz_scm_t expr,
				  zzz_scm_t * result);

/* Loads successive expressions from the standard input and evaluates
  them one after the other.  Returns 0 on success, and the error code
  @var{x} if @code{(exit @var{x})} was evaluated in the code.  */
SIZZLE_API int zzz_read_eval_print (void);

/* Initializes the evaluation module.  */
SIZZLE_API result_t zzz_init_eval (void);

/* Shuts down the evaluation module.  */
SIZZLE_API result_t zzz_finalize_eval (void);

/* Takes a list and returns non-null if list contains duplicate
   entries in the sense of `eq?'.  */
SIZZLE_API int zzz_int_check_list_for_dups (zzz_scm_t list);

/* Return 1 if any list element is not a symbol, 0 otherwise.  */
SIZZLE_API int zzz_int_check_list_for_non_symbols (zzz_scm_t list);

/* Checks whether the list @var{list} is in the format expected by the
   various @code{let} constructs.  Returns @code{RESULT_SUCCESS} if
   okay, or an error code and an error object is stored in the
   location pointed to by @var{result}.  */
SIZZLE_API result_t zzz_int_check_let_formals (char * func_name, 
					       zzz_scm_t list,
					       zzz_scm_t * result);

/* Load the file named @var{filename} into the current toplevel
   environment.  */
SIZZLE_API result_t zzz_primitive_load_path (zzz_scm_t env, zzz_scm_t filename,
					     zzz_scm_t * result);

/* Load and evaluate all expressions from the port @var{port} in the
   environment @var{env}.  */
SIZZLE_API result_t zzz_load_port (zzz_scm_t env, zzz_scm_t port,
				   zzz_scm_t * result);

/* Report the error or exception of kind @var{err} with error object
   @var{error} to the current standard error port.  @var{interactive}
   should be non-zero, if called from an interactive repl.  */
SIZZLE_API void zzz_report_error (result_t err, zzz_scm_t error,
				  int interactive);

/* Create a @code{wrong-number-args} exception with the additional
   arguments @var{args}.  */
SIZZLE_API zzz_scm_t zzz_make_wna_exception (zzz_scm_t args);

/* Create a @code{wrong-type-argument} exception with the additional
   arguments @var{args}.  */
SIZZLE_API zzz_scm_t zzz_make_wta_exception (zzz_scm_t args);

/* Create a @code{misc-error} exception with the additional arguments
   @var{args}.  */
SIZZLE_API zzz_scm_t zzz_make_misc_error_exception (zzz_scm_t args);

#endif /* not __SIZZLE_EVAL_H__ */
