/* libsizzle/node.h - basic data types

  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_NODE_H__
#define __SIZZLE_NODE_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 <stdlib.h>
#include <setjmp.h>

#include "result.h"
#include "gc.h"


/* Immediate values for some important constants.  More may be added
   to this list, but make sure they to not overlap with the immediate
   codes below.  */
#define imm_false        (((zzz_object_t) (1 << 3)) | 3)
#define imm_true         (((zzz_object_t) (2 << 3)) | 3)
#define imm_unspecified  (((zzz_object_t) (3 << 3)) | 3)
#define imm_undefined    (((zzz_object_t) (4 << 3)) | 3)
#define imm_eof_object   (((zzz_object_t) (5 << 3)) | 3)

/* Immediate codes.  They replace calls to special forms and are
   evaluated inline when they are encountered again.  */
#define imm_if_then      (((zzz_object_t) (31 << 3)) | 3)
#define imm_if_then_else (((zzz_object_t) (32 << 3)) | 3)
#define imm_begin        (((zzz_object_t) (33 << 3)) | 3)
#define imm_let          (((zzz_object_t) (34 << 3)) | 3)
#define imm_letrec       (((zzz_object_t) (35 << 3)) | 3)
#define imm_letstar      (((zzz_object_t) (36 << 3)) | 3)
#define imm_set_x        (((zzz_object_t) (37 << 3)) | 3)
#define imm_define       (((zzz_object_t) (38 << 3)) | 3)
#define imm_and          (((zzz_object_t) (39 << 3)) | 3)
#define imm_or           (((zzz_object_t) (40 << 3)) | 3)
#define imm_cond         (((zzz_object_t) (41 << 3)) | 3)
#define imm_case         (((zzz_object_t) (42 << 3)) | 3)
#define imm_do           (((zzz_object_t) (43 << 3)) | 3)
#define imm_named_let    (((zzz_object_t) (44 << 3)) | 3)
#define imm_quote        (((zzz_object_t) (45 << 3)) | 3)
#define imm_quasiquote   (((zzz_object_t) (46 << 3)) | 3)
#define imm_lambda       (((zzz_object_t) (47 << 3)) | 3)
#define imm_definefunc   (((zzz_object_t) (48 << 3)) | 3)
#define imm_defineconst  (((zzz_object_t) (49 << 3)) | 3)
#define imm_undefine     (((zzz_object_t) (50 << 3)) | 3)
#define imm_delay        (((zzz_object_t) (51 << 3)) | 3)

/* (c is '()) <=> null_p(c) */
#define null_p(c)        (!(c))

/* Slightly slower version of the macro above, which *must* be used
   for list traversal during garbage collection.  */
#define gc_null_p(c)     (!(unmarked(c)))

/* (c is an immediate integer value) <=> int_p(c) */
#define fixnum_p(c)      ((((zzz_object_t) (c)) & 3) == 1)

/* Get the integer value of a fixnum.  Use only if fixnum_p(c) is
   true.  */
#define fixnum_val(c)    scm_to_fixnum(c)

/* FIXME: This is 32 bit specific, but harmless on 64 bit.  Just loses
   a bit performance for large numbers.  */
#define MIN_FIXNUM (-268435456)
#define MAX_FIXNUM  (268435455)

/* (c is any immediate value)     <=> imm_p(c)

   This definition of imm_p(c) is equivalent to 
     (null_p(c) || fixnum_p(c) || immediate_p(c)) 
   but gets faster by only checking whether the argument is zero or
   whether the least significant bit is set. */

#define imm_p(c)         (null_p(c) || (((zzz_object_t) (c) & 1) == 1))

/* This version of the imm_p() macro *must* be used during garbage
   collection.  */
#define gc_imm_p(c)      (gc_null_p(c) || (((zzz_object_t) (c) & 1) == 1))

/* (c is an immediate form) <=> imm_form_p(c) */
#define immediate_p(c)   (((zzz_object_t) (c) & 3) == 3)

/* Get the value of an immediate object.  */
#define immediate_val(c) (((zzz_object_t) (c)) & 0xffff)

/* (c is a pointer to a cons cell) <=> cons_p(c) */
#define cons_p(c)        (!imm_p(c) && (((zzz_object_t) (c)) & 3) == 0)

/* This version of the cons_p() macro *must* be used during garbage
   collection.  */
#define gc_cons_p(c)     (!gc_imm_p(c) && (((zzz_object_t) (c)) & 3) == 0)

/* (c is a (possibly empty) list) <=> list_p(c) */
#define list_p(c)        (null_p(c) || cons_p(c))

/* (c is a (immediate or long) integer) <=> integer_p(c) */
#define integer_p(c)     (fixnum_p(c) || long_p(c))

/* Get the value of any integer object.  Use only if integer_p(c) is
   true. */
#define integer_val(c)   (fixnum_p(c) ? fixnum_val(c) : long_val(c))

/* (c is a procedure) <=> procedure_p(c) */
#define procedure_p(c)   (func_p(c)||closure_p(c)||form_p(c))

/* (c is a number) <=> number_p(c) */
#define number_p(c)      (integer_p(c) || float_p(c))

/* Convert any cell value to a pointer.  Make sure C actually points
 * to either a cons or a tagged cell.  */
#define to_ptr(c)    ((void *) (((zzz_object_t) (c)) & ~7))

/* Get the elements of a cons cell.  Use only when (nimm_p(c)).  */
#if 1
#define car(c)           ((c)->ccar)
#define cdr(c)           ((c)->ccdr)
#endif
#ifndef car
SIZZLE_API zzz_scm_t car (zzz_scm_t cons);
#endif
#ifndef cdr
SIZZLE_API zzz_scm_t cdr (zzz_scm_t cons);
#endif

#if 1
#define set_car(c, v)    ((c)->ccar) = v
#define set_cdr(c, v)    ((c)->ccdr) = v
#endif
#ifndef set_car
SIZZLE_API void set_car (zzz_scm_t cons, zzz_scm_t val);
#endif
#ifndef set_cdr
SIZZLE_API void set_cdr (zzz_scm_t cons, zzz_scm_t val);
#endif

#if 1
#define car_addr(c)      (&((c)->ccar))
#define cdr_addr(c)      (&((c)->ccdr))
#endif
#ifndef car_addr
SIZZLE_API zzz_scm_t * car_addr (zzz_scm_t cons);
#endif
#ifndef cdr_addr
SIZZLE_API zzz_scm_t * cdr_addr (zzz_scm_t cons);
#endif

/* Convert a Scheme object known to be a fixnum to a long integer.  */
#define scm_to_fixnum(c) ((long) (((long) (c)) >> 3))

/* Convert a long integer value known to fit into a fixnum object to a
   fixnum.  */
#define fixnum_to_scm(i) ((zzz_scm_t) ((((zzz_signed_object_t)(i)) << 3) + 1))

/* `Official' method for converting integer values to fixnums.  Use
   only of you are sure that the parameter will fit into a fixnum, use
   zzz_make_integer() if not sure.  */
#define zzz_make_fixnum(i) fixnum_to_scm(i)

/* (c is a pointer to a tagged cell) <=> tagged_p(c) */
#define tagged_p(c)      ((((zzz_object_t) (c)) & 3) == 2)

/* Convert a pointer into the tagged cell heap to a tagged object
   pointer.  */
#define ptr_to_tagged(c) ((zzz_tagged_t) (((zzz_object_t) (c)) + 2))

/* Convert a tagged object pointer to an aligned pointer into the
   tagged heap.  */
#define to_tagged_ptr(p) ((zzz_tagged_t) (((zzz_object_t) (p)) & ~7))

/* Return the type of an object known to be a tagged object.  */
#define tagged_type(c)   (((zzz_object_t) (to_tagged_ptr(c))->fill[0] >> 3)\
                          & 0xffff)

/* Return the info field of a tagged object.  */
#define tagged_info(c)   (((zzz_object_t) (to_tagged_ptr(c))->fill[0] >> 3)\
                           & ~0xffff)

/* Get data from the data slots of a tagged object.  */
#define tagged_data0(c)  ((void *) (to_tagged_ptr(c))->fill[1])
#define tagged_data1(c)  ((void *) (to_tagged_ptr(c))->fill[2])
#define tagged_data2(c)  ((void *) (to_tagged_ptr(c))->fill[3])

/*
  The following macros are type predicates and accessor macros for
  various tagged types.
 */

#define string_p(c)      (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_string)
#define ro_string_p(c)   (string_p(c) && \
                          tagged_info(c) == tagged_info_ro)
#define string_val(c)    ((char *) tagged_data0(c))
#define string_len(c)    ((unsigned) ((zzz_object_t) tagged_data1(c)))

#define bool_p(c)        (immediate_p(c) && \
                          ((immediate_val(c) == imm_false) || \
                           (immediate_val(c) == imm_true)))
#define bool_val(c)      ((immediate_val(c) == imm_false) ? 0 : 1)

#define char_p(c)        (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_char)
#define char_val(c)      ((unsigned) ((zzz_object_t) tagged_data0(c)))

#define float_p(c)       (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_float)
#define float_val(c)     (*((double *) (to_tagged_ptr(c)->fill + 2)))

#define symbol_p(c)      (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_symbol)
#define symbol_name(c)   ((zzz_scm_t) tagged_data0(c))
#define symbol_value(c)  ((zzz_scm_t) tagged_data1(c))
#define symbol_name_addr(c)   ((zzz_scm_t *) (&(to_tagged_ptr(c)->fill[1])))
#define symbol_value_addr(c)  ((zzz_scm_t *) (&(to_tagged_ptr(c)->fill[2])))
#define set_symbol_name(c, s) ((zzz_tagged_t) to_tagged_ptr(c))->fill[1] = \
                          (zzz_object_t) (s)
#define set_symbol_value(c, s) ((zzz_tagged_t) to_tagged_ptr(c))->fill[2] = \
                          (zzz_object_t) (s)

#define func_p(c)        (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_func)
#define form_p(c)        (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_form)
#define func_ptr(c)      (((zzz_func_desc_t) tagged_data0(c))->func)
#define func_name(c)     (((zzz_func_desc_t) tagged_data0(c))->name)
#define func_form_p(c)   (((zzz_func_desc_t) tagged_data0(c))->is_form)
#define func_doc(c)      (((zzz_func_desc_t) tagged_data0(c))->documentation)
#define func_param(c)    (tagged_info(c))
#define func_traced_p(c) (((zzz_func_desc_t) tagged_data0(c))->traced_p)

#define lambda_p(c)      (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_lambda)
#define lambda_name(c)   (((zzz_lambda_desc_t) tagged_data0(c))->name)
#define lambda_args(c)   (((zzz_lambda_desc_t) tagged_data0(c))->args)
#define lambda_body(c)   (((zzz_lambda_desc_t) tagged_data0(c))->body)
#define lambda_doc(c)    (((zzz_lambda_desc_t) tagged_data0(c))->documentation)
#define lambda_traced_p(c) (((zzz_lambda_desc_t) tagged_data0(c))->traced_p)

#define closure_p(c)     (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_closure)
#define closure_proc(c)  ((zzz_scm_t) tagged_data0(c))
#define closure_env(c)   ((zzz_scm_t) tagged_data1(c))

#define error_p(c)       (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_error)

#define except_p(c)      (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_except)

#define long_p(c)        (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_long)
#define long_val(c)      ((long) tagged_data0(c))

#define env_p(c)         (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_environment)
#define env_val(c)       ((zzz_scm_t) tagged_data0(c))
#define env_link(c)      ((zzz_scm_t) tagged_data1(c))

/* This constant is used when creating environments for let
   expressions and lambda environments.  */
#define ENVIRONMENT_SIZE (11)

#define location_p(c)    (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_location)
#define ro_location_p(c) (location_p (c) && \
                          tagged_info(c) == tagged_info_ro)
#define location_address(c) ((zzz_scm_t *) tagged_data0(c))

#define lloc_p(c)        (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_lloc)
#if 0
#define lloc_val(c)      ((zzz_scm_t) tagged_data0(c))
#endif
#define lloc_env(c)      ((zzz_scm_t) tagged_data0(c))
#define lloc_slot(c)     ((zzz_scm_t) tagged_data1(c))
#define lloc_symbol(c)   ((zzz_scm_t) tagged_data2(c))

#define gloc_p(c)        (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_gloc)
#define gloc_name(c)     ((zzz_scm_t) tagged_data0(c))
#define gloc_val(c)      ((zzz_scm_t *) tagged_data1(c))

#define constant_p(c)    (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_constant)
#define constant_val(c)  ((zzz_scm_t) tagged_data0(c))

#define keyword_p(c)     (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_keyword)
#define keyword_name(c)  ((zzz_scm_t) tagged_data0(c))

#define pointer_p(c)     (tagged_p(c) && \
                          tagged_type(c) == zzz_tagged_type_pointer)
#define valid_pointer_p(c) (pointer_p(c) && pointer_valid(c))
#define pointer_val(c)   ((void *) tagged_data0(c))
#define pointer_len(c)   ((zzz_object_t) tagged_data1(c))
#define pointer_valid(c) (tagged_data2(c))

/* Use only when (nimm_p(c)).
  (c points to marked cell)   <=> marked_p(c) */
#define marked_p(c)      ((*((zzz_object_t *) to_ptr(c)) & 4) != 0)

/* mark_car() marks the cell pointed to by c as marked, unmark_car()
  unmarks the cell pointed to by c.  */
#define mark_car(c)      (*((zzz_object_t *) to_ptr(c))) |= 4
#define unmark_car(c)    (*((zzz_object_t *) to_ptr(c))) &= ~4

/* Mask out the mark bit of c.  */
#define unmarked(c)      ((zzz_scm_t) ((zzz_object_t) (c) & ~4))

/* Generic prototype for defining primitive procedures and syntactic
   forms.  */
typedef result_t (* zzz_prim_t)(zzz_scm_t env, zzz_scm_t expr,
				zzz_scm_t * result);

/* Return true if @var{o} is the undefined object.  */
#define undefined_p(o)   (zzz_eq ((o), zzz_undefined))

/* 
   Various info values for tagged objects.
 */

/* Used for strings, vectors, indirect variables etc. */
#define tagged_info_ro         (1 << 16)

/* Used for environments which form the end of a static link chain.  */
#define tagged_info_final      (2 << 16)

/* Use in environments to mark that environments below the current are
   read-only.  (e.g. the current environment *is* writable, but the
   chained environments are not.)*/
#define tagged_info_ro_chain   (4 << 16)

/* These are stored in the info field of procedure objects.  They
   define the expected parameter format of the primitive.  The first
   digit is the number of required parameters, the second the number
   of optional parameters and the last one is 0 if no rest parameters
   are allowed and 1 if they are.  */
#define argv_0_0_1  (0 << 16)
#define argv_0_0_0  (1 << 16)
#define argv_1_0_0  (2 << 16)
#define argv_2_0_0  (3 << 16)
#define argv_3_0_0  (4 << 16)
#define argv_4_0_0  (5 << 16)
#define argv_5_0_0  (6 << 16)
#define argv_0_1_0  (7 << 16)
#define argv_1_1_0  (8 << 16)
#define argv_2_1_0  (9 << 16)
#define argv_1_0_1  (10 << 16)
#define argv_2_2_0  (11 << 16)
#define argv_3_3_0  (12 << 16)
#define argv_1_2_0  (13 << 16)
#define argv_2_0_1  (14 << 16)
#define argv_0_2_0  (15 << 16)
#define argv_1_3_0  (16 << 16)
#define argv_2_4_0  (17 << 16)
#define argv_2_3_0  (18 << 16)
#define argv_6_0_0  (19 << 16)
#define argv_7_0_0  (20 << 16)

/* Stored in the info field of syntactic form objects.  If set, the
   primitive implementing the form does only rewrite the code calling
   the form, but not execute it.  It will cause the evaluator to loop
   once for preprocessing forms to get to the replaced immediate code
   value.  */
#define argv_prep_form  (1 << 16)

/* Various pre-defined tag values.  */
SIZZLE_API extern zzz_object_t zzz_tagged_type_free;
SIZZLE_API extern zzz_object_t zzz_tagged_type_string;
SIZZLE_API extern zzz_object_t zzz_tagged_type_char;
SIZZLE_API extern zzz_object_t zzz_tagged_type_float;
SIZZLE_API extern zzz_object_t zzz_tagged_type_symbol;
SIZZLE_API extern zzz_object_t zzz_tagged_type_func;
SIZZLE_API extern zzz_object_t zzz_tagged_type_form;
SIZZLE_API extern zzz_object_t zzz_tagged_type_lambda;
SIZZLE_API extern zzz_object_t zzz_tagged_type_error;
SIZZLE_API extern zzz_object_t zzz_tagged_type_except;
SIZZLE_API extern zzz_object_t zzz_tagged_type_long;
SIZZLE_API extern zzz_object_t zzz_tagged_type_environment;
SIZZLE_API extern zzz_object_t zzz_tagged_type_location;
SIZZLE_API extern zzz_object_t zzz_tagged_type_lloc;
SIZZLE_API extern zzz_object_t zzz_tagged_type_gloc;
SIZZLE_API extern zzz_object_t zzz_tagged_type_constant;
SIZZLE_API extern zzz_object_t zzz_tagged_type_keyword;
SIZZLE_API extern zzz_object_t zzz_tagged_type_closure;
SIZZLE_API extern zzz_object_t zzz_tagged_type_pointer;

/* Predefined values (#t, #f, #<eof-object> etc.) */
#define zzz_false_value ((zzz_scm_t) imm_false)
#define zzz_true_value  ((zzz_scm_t) imm_true)
#define zzz_unspecified ((zzz_scm_t) imm_unspecified)
#define zzz_undefined   ((zzz_scm_t) imm_undefined)
#define zzz_eof_object  ((zzz_scm_t) imm_eof_object)

/* Some symbols the interpreter needs to know about, such as `else',
   `quote', etc.  */
SIZZLE_API extern zzz_scm_t zzz_else_sym;
SIZZLE_API extern zzz_scm_t zzz_quote_sym;
SIZZLE_API extern zzz_scm_t zzz_quasiquote_sym;
SIZZLE_API extern zzz_scm_t zzz_unquote_sym;
SIZZLE_API extern zzz_scm_t zzz_unquote_splicing_sym;
SIZZLE_API extern zzz_scm_t zzz_dot_sym;
SIZZLE_API extern zzz_scm_t zzz_dots_sym;
SIZZLE_API extern zzz_scm_t zzz_arrow_sym;

/* This holds the symbol `not-available', which is used in exceptions
   thrown for primitives not available on the current system.  */
SIZZLE_API extern zzz_scm_t zzz_not_available_exception;

/* The table where the objects for all characters are stored.  */
SIZZLE_API extern zzz_scm_t zzz_char_values[];

/* The table where all defined symbols are stored together with their
   top-level bindings.  */
SIZZLE_API extern zzz_scm_t zzz_symbol_table;

/* Table where all keywords are stored.  */
SIZZLE_API extern zzz_scm_t zzz_keyword_table;

/* The environment where all library definitions should take place.  */
SIZZLE_API extern zzz_scm_t zzz_library_environment;

/* This is the environment where all current top-level definitions are
   stored.  */
SIZZLE_API extern zzz_scm_t zzz_current_environment;

/* Interaction environment, this is the environment in which the user
   init file is parsed and in which REPL expressions are evaluated.  */
SIZZLE_API extern zzz_scm_t zzz_interaction_environment;

/* XXX: This is for backward compatibility and will be removed ASAP.  */
#define zzz_toplevel_env zzz_interaction_environment

/* Holds the module in which currently definitions take place.  */
SIZZLE_API extern zzz_scm_t zzz_current_module;

/* This holds a list of command line arguments available to Scheme
   code via the procedure @code{command-line}.  */
SIZZLE_API extern zzz_scm_t zzz_command_line_list;

/* Holds the backtrace list. */
SIZZLE_API extern zzz_scm_t zzz_backtrace;



/* Create a fixnum object with integer value @var{number}.  If
   @var{number} does not fit into the range of fixnums, its high bits
   are silently truncated.  The fixnum range is between -268435456 and
   268435455, inclusive.  */
#ifndef zzz_make_fixnum
SIZZLE_API zzz_scm_t zzz_make_fixnum (long number);
#endif /* !defined(zzz_make_fixnum) */

/* Create an integer object with value @var{value}.  A fixnum is
   returned if @var{value} fits into the range defined for fixnums,
   otherwise a long object is returned which holds all 32 bits of
   information from @var{value}.  */
SIZZLE_API zzz_scm_t zzz_make_integer (long value);

/* Create a string of length @var{len} and initialize with the data
   pointed to by @var{s}.  If @var{len} is less than zero, @var{s} is
   considered a nul-terminated string and the length is calculated by
   using strlen().  */
SIZZLE_API zzz_scm_t zzz_make_string (char * s, int len);

/* Create a constant string of length @var{len} and initialize with
   the data pointed to by @var{s}.  If @var{len} is less than zero,
   @var{s} is considered a nul-terminated string and the length is
   calculated by using strlen().  The returned string is read-only and
   cannot be modified with Scheme primitives like @code{string-set!}.  */
SIZZLE_API zzz_scm_t zzz_make_ro_string (char * s, int len);

/* Create a string of length @var{len}.  The contents of the returned
   string is unspecified.  */
SIZZLE_API zzz_scm_t zzz_make_nstring (int len);

/* Create a constant string of length @var{len}.  The contents of the
   returned string is unspecified.  The returned string is read-only
   and cannot be modified with Scheme primitives like
   @var{string-set!}.  */
SIZZLE_API zzz_scm_t zzz_make_ro_nstring (int len);

/* Create a boolean object.  If @var{b} is zero, the false Scheme
   object @code{#f} is returned, otherwise the generic true Scheme
   object @code{#t} is returned.  */
SIZZLE_API zzz_scm_t zzz_make_bool (long b);

/* Create a character object with character value @var{b}.  Only the
   lower 8 bits of @var{b} are actually used.  */
SIZZLE_API zzz_scm_t zzz_make_char (long b);

/* Create a real number object initialized with the value of @var{d}.  */
SIZZLE_API zzz_scm_t zzz_make_float (double d);

/* Create a Scheme symbol with the string representation @var{s} of
   length @var{len}.  If @var{len} is less than zero, strlen(@var{s})
   is used to determine the string length.  This function will return
   the same object for all strings with the same length and the same
   character contents.  */
SIZZLE_API zzz_scm_t zzz_make_symbol (char * s, int len);

/* Create a primitive function object.  @var{func} is the address of
   the C function that handles the primitive function, @var{name} is
   the name under which the function will be available in Scheme,
   @var{form} should be 0 for primitive functions and non-zero of
   syntax forms and @var{param_format} is a description of the
   parameter format the function expects.  Use one of the
   @code{argv_*_*_*} constants for this parameter.  */
SIZZLE_API zzz_scm_t zzz_make_func (zzz_prim_t func, char * name, int form,
				    int param_format);

/* Create a lambda object.  @var{expr} must be a list where the car is
   the formal parameter list and the cdr must be the procedure body.  */
SIZZLE_API zzz_scm_t zzz_make_lambda (zzz_scm_t expr);

/* Create a closure object which closes the procedure @var{proc} under
   the environment @var{env}.  */
SIZZLE_API zzz_scm_t zzz_make_closure (zzz_scm_t proc, zzz_scm_t env);

/* Create an error object.  @var{msg} is the error message,
   @var{reference} is a list containing the file name, line number and
   column number where the error occurred; or NULL if that information
   is not available.  */
SIZZLE_API zzz_scm_t zzz_make_error (zzz_scm_t msg, zzz_scm_t reference);

/* Set the reference field of the error object @var{error} to
   @var{reference}.  */
SIZZLE_API void zzz_set_error_reference (zzz_scm_t error, zzz_scm_t reference);

/* Set the reference field of the exception object @var{error} to
   @var{reference}.  */
SIZZLE_API void zzz_set_exception_reference (zzz_scm_t exception,
					     zzz_scm_t reference);

/* Create an exception object. @var{exception} is the exception tag
   (any atom) and @var{msg} is the exception message which may hold
   additional information about the exception.  */
SIZZLE_API zzz_scm_t zzz_make_exception (zzz_scm_t exception, zzz_scm_t msg);

/* Create an environment object.  @var{static_link} is the link to the
   including lexical environment in which variable bindings will be
   searched.  When @var{final} is true, the static link will not be
   followed beyond this environment object and when @var{read_only} is
   true, no modifications to the environment will be allowed.  */
SIZZLE_API zzz_scm_t zzz_make_environment (unsigned size, 
					   zzz_scm_t static_link,
					   int final, int read_only);

/* Create a location object.  A location object is an indirect object
   which refers to a Scheme object variable address.  @var{location}
   points to the location to redirect to and @var{read_only} specified
   whether this location may be written to.  */
SIZZLE_API zzz_scm_t zzz_make_location (zzz_scm_t * location, int read_only);

/* Create a lloc object.  A lloc object is substituted for all local
   variables which have been looked up once and which are not special
   variables.  They are used to cache the location of variables and to
   speed up references to local variables.  @var{symbol} is the
   variable name this lloc stands for, @var{env_ofs} is the number of
   environments to traverse down the static link and @var{hash_val} is
   the hash index into the environment where we have to search for
   @var{symbol}.  */
SIZZLE_API zzz_scm_t zzz_make_lloc (zzz_scm_t symbol, int env_ofs, int offset);

/* Create a gloc object.  A gloc is similar to a lloc, but only
   applies to global variables not in an environment, but in the
   symbol table.  @var{name} is the variable name this gloc stands
   for, and @var{address} is the location where the value of the
   variable can be found.  */
SIZZLE_API zzz_scm_t zzz_make_gloc (zzz_scm_t name, zzz_scm_t * address);

/* Create a constant object with value @var{value}.  A constant object
   is special, since it value may be substituted whenever it is
   referenced, and therefore references are faster than variable
   references.  Also variables containing constant objects can not be
   modified.  */
SIZZLE_API zzz_scm_t zzz_make_constant (zzz_scm_t value);

/* Create a Scheme keyword object with the string representation
   @var{s} of length @var{len}.  If @var{len} is less than zero,
   strlen(@var{s}) is used to determine the string length.  This
   function will return the same object for all strings with the same
   length and the same character contents.  Keywords are similar to
   symbols, but are self-evaluating and must therefore not be quoted
   in Scheme code.  */
SIZZLE_API zzz_scm_t zzz_make_keyword (char * s, int len);

/* Create a pointer object which referencing @var{address}.  */
SIZZLE_API zzz_scm_t zzz_make_pointer (void * address);

/* Create a pointer object which referencing a memory area starting at
   @var{address} and being @var{n} bytes long.  */
SIZZLE_API zzz_scm_t zzz_make_pointer_n (void * address, unsigned n);

/* Create a Scheme list of all parameters.  @var{first} is the first
   element of the resulting list, followed by the optional parameters.
   The parameter list must be terminated with a NULL pointer.  */
SIZZLE_API zzz_scm_t zzz_make_list (zzz_scm_t first, ...);

/* Create a Scheme list of exactly @var{n} parameters.  @var{first} is
   the first element of the resulting list, followed by the optional
   parameters. */
SIZZLE_API zzz_scm_t zzz_make_n_list (int n, zzz_scm_t first, ...);

/* Make a copy of the list @var{list}.  Note that @var{list} must be a
   proper list.  This function only copies the spine of the list, that
   means, that the list elements are shared, and only the cons cells
   construcing the list are newly allocated.  If you need to make a
   deep copy of a list, use @code{zzz_copy_tree()} instead.  */
SIZZLE_API zzz_scm_t zzz_copy_list (zzz_scm_t list);

/* Make a deep copy of the object @var{tree}.  That means, that
   vectors and pairs are cloned recursively and all other objects are
   simply copied to the returned object.  */
SIZZLE_API zzz_scm_t zzz_copy_tree (zzz_scm_t tree);



SIZZLE_API zzz_scm_t zzz_make_not_available_exception (zzz_scm_t args);



/* Print state handling.  This will be replaced ASAP. ------------- */

/* Printing state. */
typedef struct zzz_print_state * zzz_print_state_t;
struct zzz_print_state
{
  int flags;
};

#define PRINT_NEWLINE 0x01
#define PRINT_QUOTE   0x02
#define PRINT_ESCAPE  0x04

#if 0
/* Global print state as used by @code{write}.  Use this for debugging
   output from Scheme code.  */
SIZZLE_API extern struct zzz_print_state zzz_print_state;
#endif



/* Definitions for tagged types. ---------------------------------- */

/* This descriptor is stored in the first data word of function and
   form cells.  */
typedef struct zzz_func_descriptor * zzz_func_desc_t;
struct zzz_func_descriptor
{
  zzz_scm_t name;		/* Scheme name of the function/form.  */
  zzz_prim_t func;		/* Function pointer to be called.  */
  zzz_scm_t documentation;	/* Primitive procedure doc string or '(). */
  int is_form;			/* 1 if syntactic form, 0 otherwise.  */
  int traced_p;			/* > 0 if currently traced.  */
};

/* This descriptor is stored in the first data word of lambda cells.  */
typedef struct zzz_lambda_descriptor * zzz_lambda_desc_t;
struct zzz_lambda_descriptor
{
  zzz_scm_t name;		/* Function name or () if anonymous. */
  zzz_scm_t args;		/* Formal argument list. */
  zzz_scm_t body;		/* Lambda expression body. */
  zzz_scm_t documentation;	/* Procedure doc string.  */
  int printing;			/* Print in progress... */
  int traced_p;			/* > 0 if currently traced.  */
};



/* Tagged type management. ---------------------------------------- */

/* These are the function types defined on all tagged types.  */
typedef void * (* constructor_func_t) (zzz_tagged_t tagged, void * data0,
				       void * data1, void * data2);
typedef void (* print_func_t) (zzz_scm_t port, zzz_tagged_t tagged,
			       zzz_print_state_t state);
typedef void (* free_func_t) (zzz_tagged_t tagged);
typedef void (* mark_func_t) (zzz_tagged_t tagged);
typedef int (* equal_func_t) (zzz_tagged_t tagged0, zzz_tagged_t tagged1);

/* This data structure is used to store information about tagged
   types.  It tells the runtime system how values of the type are
   constructed, printed and marked for GC protection and how to
   release memory allocated by instances of the type and how to check
   the types for equality. */
struct zzz_type_descriptor
{
  constructor_func_t constructor_func; /* This must not be NULL.  */
  print_func_t print_func;	/* This must not be NULL.  */
  free_func_t free_func;	/* May be NULL.  */
  mark_func_t mark_func;	/* May be NULL.  */
  equal_func_t equal_func;	/* May be NULL.  */
};

/* This is the count of currently registered tagged types. */
SIZZLE_API extern zzz_object_t zzz_type_descriptor_count;

/* This is the array which holds the tagged type descriptors.  It is
   indexed by the type tags. */
SIZZLE_API extern struct zzz_type_descriptor zzz_type_descriptors[];

/* Function to create a new tagged type.  Returns the type tag. */
SIZZLE_API zzz_object_t zzz_define_tagged_type 
 (constructor_func_t constructor_func,
  print_func_t print_func,
  free_func_t free_func,
  mark_func_t mark_func,
  equal_func_t equal_func);

/* This is the default constructor function for tagged types.  It
   simply stores the passed data pointers into the tagged cell data
   fields.  Returns the tagged cell pointer passed in.  */
SIZZLE_API void * zzz_simple_constructor (zzz_tagged_t tagged, void * data0,
					  void * data1, void * data2);

/* Default mark function for tagged types.  Treats all data fields as
   of type @code{zzz_scm_t} and marks the objects pointed to by the
   data fields using zzz_mark_cell().  */
SIZZLE_API void zzz_simple_mark (zzz_tagged_t tagged);



/* Equality tests. ------------------------------------------------ */

/* Return 1 if @var{first} and @var{second} denote the same object, 0
   otherwise.  */
#define zzz_eq(first, second)	((first) == (second))
#ifndef zzz_eq
SIZZLE_API int zzz_eq (zzz_scm_t first, zzz_scm_t second);
#endif /* !defined(zzz_eq) */

/* Return 1 if @var{first} and @var{second} have the same value, 0
   otherwise.  */
SIZZLE_API int zzz_eqv (zzz_scm_t first, zzz_scm_t second);

/* Return 1 if @var{first} and @var{second} are structurally
   equivalent, 0 otherwise.  */
SIZZLE_API int zzz_equal (zzz_scm_t first, zzz_scm_t second);



/* Variable handling. --------------------------------------------- */

/* Get the object to which the variable @var{symbol} is bound in the
   environment @var{env} and store it into the variable pointed to by
   @var{value}.  If an error occurs, the return value is
   @code{RESULT_EXCEPTION} and an appropriate exception object is
   stored into the variable pointed to by @var{value}.  When @var{all}
   is non-zero, not only the environment chain is examined, but also
   the global symbol bindings in the symbol table.  */
SIZZLE_API result_t zzz_get_symbol_value_ext (zzz_scm_t env, zzz_scm_t symbol,
					      zzz_scm_t * value, int all);

/* Like zzz_get_symbol_value_ext(), but always search *all*
   environments in the environment chain of @var{env}.  */
SIZZLE_API result_t zzz_get_symbol_value (zzz_scm_t env, zzz_scm_t symbol,
					  zzz_scm_t * value);

/* Return a location object for the variable called @var{symbol} in
   the environment @var{env}.  The returned object may be either a
   @var{gloc}, if @var{symbol} is bound globally, a @var{lloc}, if
   @var{symbol} is bound locally or @var{symbol} itself, if
   @var{symbol} is bound to a C variable, which is not representable.  */
SIZZLE_API zzz_scm_t zzz_get_variable_location (zzz_scm_t env,
						zzz_scm_t symbol);

/* Set the value of the variable named @var{symbol} in environment
   @var{env} to @var{value}.  On error, return @code{RESULT_EXCEPTION}
   and store an exception object in the location pointed to by
   @var{result}.  */
SIZZLE_API result_t zzz_set_symbol_value (zzz_scm_t env, zzz_scm_t symbol,
					  zzz_scm_t value,
					  zzz_scm_t * result);

/* Define the symbol @var{symbol} with value @var{value} int the
   environment @var{env}.  On error, return @code{RESULT_EXCEPTION}
   and store an exception object in the location pointed to by
   @var{result}.  */
SIZZLE_API result_t zzz_define_symbol_value (zzz_scm_t env, zzz_scm_t symbol,
					     zzz_scm_t value,
					     zzz_scm_t * result);

/* Make the symbol @var{symbol} undefined in the environment
   @var{env}.  */
SIZZLE_API result_t zzz_undefine_symbol (zzz_scm_t env, zzz_scm_t symbol,
					 zzz_scm_t * result);

/* General API functions. ----------------------------------------- */

/* Initialize the Sizzle library.  */
SIZZLE_API void zzz_initialize (void);

/* Free all resources taken by the Sizzle library and call the
   shutdown hooks.  */
SIZZLE_API void zzz_finalize (void);

/* Initialize the interpreter and call the function @var{main} with
   parameters @var{argc} and @var{argv}. */
SIZZLE_API int zzz_run (int (* main)(int argc, char * argv[]), int argc,
			char * argv[]);

/* Make command line arguments available to the Scheme code in the
   variable @code{%command-line%}.  @var{argc} is the number of
   elements in @var{argv}, @var{arg0} is the program name which will
   be the first element of the command line.  */
SIZZLE_API void zzz_set_arguments (int argc, char * argv0, char * argv[]);

/* Use this for debugging output of Scheme values.  */
#define DEBUG_OUT(s)						\
  do								\
    {								\
      zzz_scm_t result;						\
      zzz_port_print (zzz_current_err_port,			\
		      (s), &zzz_print_state, &result);		\
      zzz_port_putc ('\n', zzz_current_err_port, &result);	\
    }								\
  while (0)

/* Function type for hook functions.  The parameter @var{data} will be
   the pointer given when the hook was registered.  */
typedef result_t (* hook_func_t) (void * data);

/* Install the hook function @var{hook} as a shutdown hook.  It will
   be called when the library shuts down with @var{data} as the only
   parameter.  */
SIZZLE_API void zzz_install_shutdown_hook (hook_func_t hook, void * data);

/* Install the hook function @var{hook} as an after mark hook.  It will
   be called whenever the mark phase of GC terminates.  */
SIZZLE_API void zzz_install_after_mark_hook (hook_func_t hook, void * data);

/* Install the hook function @var{hook} as an after mark hook.  It will
   be called whenever the sweep phase of GC terminates.  */
SIZZLE_API void zzz_install_after_sweep_hook (hook_func_t hook, void * data);

SIZZLE_API void zzz_run_after_mark_hook (void);
SIZZLE_API void zzz_run_after_sweep_hook (void);

struct zzz_state
{
  /* Generic state ------------------------------------------------ */

  /* Global print state variable which can be used in calls to
     `zzz_port_print()' when full quoting is desired.  */
  struct zzz_print_state print_state;
  
  /* Object management -------------------------------------------- */

  /* If true, glocs and llocs make themselves visible on printing.  */
  int print_memoized;
  
  /* If true, procedures are printed with their procedure bodies.  */
  int print_func_bodies;
  
  /* Reader ------------------------------------------------------- */

  int parentheses_nesting;
  int remember_source_locations;
  int support_mzscheme_brackets;
/*    zzz_scm_t current_input_file_name; */

  zzz_scm_t source_locations;

  int string_buf_size;
  int string_buf_len;
  char * string_buf;


};

SIZZLE_API extern struct zzz_state zzz_state;

#endif /* not __SIZZLE_NODE_H__ */
