/* byte-object.h: -*- C -*-  DESCRIPTIVE TEXT. */

/*  Copyright (c) 1996 Universal Access Inc.
    Author: E. B. Gamble Jr. (ebg@ai.mit.edu) Sun Nov  3 11:37:27 1996.  */

/* MetaHTML objects for a call-by-refernece compiler. */

/* Most everything here is temporary and will soon be integrated with the
   real meta-HTML type. */

/* And, those references to bc_array_t/bc_tagged_object_t will likely be
   converted to C vectors of symbols - as symbols are the only objects with
   TAGS in our call-by-name language */
#if !defined (_BC_OBJECT_H_)
#define _BC_OBJECT_H_ 1

/*
 * BC_OBJECT_T
 *
 */
typedef void *bc_object_t;

#define BC_AS_OBJECT( thing )     ((bc_object_t) (thing))

/*
 * BC_TYPE_T
 *
 * These are the runtime types in MetaHTML.  These also happen to be the 
 * denotations for variables; that is, there really is only a dynamic
 * environment; there is no static environment to speak of.    
 */
typedef enum
{
  BC_STRING_TYPE,
  BC_NUMBER_TYPE,
  BC_INDEX_TYPE,
  BC_FORMAT_TYPE,
  BC_SYMBOL_TYPE,
  BC_PACKAGE_TYPE,
  BC_STREAM_TYPE,
  BC_ARRAY_TYPE,		
  BC_FUNCTION_TYPE,			/* User defined FUNCTIONS */
  BC_MACRO_TYPE,			/* User defined MACROS */
  BC_SPECIAL_FORM_TYPE,			/* Always MetaHTML - like IF */
  BC_HTML_TYPE,				/* Always HTML - like HREF */
  BC_UNBOUND_TYPE,			/* Symbol without an object */
  BC_NUMBER_OF_TYPES
} bc_type_t;

/* 
 * BC_BOOLEAN_T
 *
 */
typedef enum {
  bc_false = 0,
  bc_true  = 1,
} bc_boolean_t;


/*
 * BC_BYTE_CODE_T
 *
 * Bytecode consists of byte operators and byte operands.  The
 * bc_byte_op_t type must be coercible to bc_byte_code_t.  A byte code
 * vector is a pointer to bc_byte_code_t although we don't use an
 * expicit typedef for that.
 *
 * This declaration is here as opposed in to code.h for the benefit of
 * the upcoming bc_function_t declaration.  This is not an object in
 * MetaHTML.
 */ 
typedef unsigned char bc_byte_code_t;

/*
 * BC_STRING_T
 *
 */ 
typedef char *bc_string_t;

#define bc_string_length( string )        (strlen (string))
#define bc_string_equal( str1, str2 )     (0 == strcmp ((str1), (str2)))
#define bc_string_not_equal( str1, str2 ) (0 != strcmp ((str1), (str2)))

/* Useful Constants */
extern bc_string_t bc_object_empty;
extern bc_string_t bc_object_true;
extern bc_string_t bc_object_false;

#define BC_OBJECT_IS_EMPTY_P( object )		\
   bc_string_equal (object, bc_object_empty)
#define BC_OBJECT_IS_TRUE_P( object )		\
   bc_string_equal (object, bc_object_true)
#define BC_OBJECT_IS_FALSE_P( object )		\
   bc_string_equal (object, bc_object_false)
#define BC_OBJECT_IS_NOT_FALSE_P( object )	\
   bc_string_not_equal (object, bc_object_false)

/*
 * BC_NUMBER_T
 *
 */
typedef double       bc_number_t;
typedef unsigned int bc_index_t;

/* 
 * BC_FORMAT_T
 *
 * A list-of-objects - like an upcoming bc_array_t but easier to create
 * on-the-fly.
 */
typedef struct bc_format
{
  bc_type_t         type;
  bc_object_t       object;
  struct bc_format *next;
} *bc_format_t;

#define BC_FORMAT_TYPE( format )     ((format)->type)
#define BC_FORMAT_OBJECT( format )   ((format)->object)
#define BC_FORMAT_NEXT( format )     ((format)->next)

#define BC_FORMAT_NULL               ((bc_format_t) NULL)  

extern void
bc_format_print (bc_format_t format);

/*
 * BC_TAGGED_OBJECT_T
 *
 */
typedef struct bc_tagged_object
{
  bc_type_t   type;
  bc_object_t value;
} *bc_tagged_object_t;

#define BC_TAGGED_OBJECT_TYPE( object )    ((object)->type)
#define BC_TAGGED_OBJECT_VALUE( object )   ((object)->value)

/*
 * BC_ARRAY_T
 *
 */
typedef struct bc_array
{
  unsigned int size;
  bc_tagged_object_t objects;
} *bc_array_t;

#define BC_ARRAY_SIZE( array )        ((array)->size)
#define BC_ARRAY_OBJECTS( array )     ((array)->objects)
#define BC_ARRAY_OBJECT( array, n )   ((array)->objects[(n)])

/*
 * BC_SYMBOL_T
 *
 */
typedef struct bc_symbol
{
  bc_string_t  name;
  bc_object_t  value;
  bc_type_t    type;
  unsigned int hash;
  struct bc_symbol *next;
} *bc_symbol_t;

#define BC_SYMBOL_NAME( symbol )     ((symbol)->name)
#define BC_SYMBOL_VALUE( symbol )    ((symbol)->value)
#define BC_SYMBOL_TYPE( symbol )     ((symbol)->type)
#define BC_SYMBOL_HASH( symbol )     ((symbol)->hash)
#define BC_SYMBOL_NEXT( symbol )     ((symbol)->next)

extern bc_symbol_t bc_list_of_symbols;

extern bc_symbol_t
bc_symbol_intern (bc_string_t string);

extern bc_symbol_t
bc_symbol_find (bc_string_t string);

/*
 * BC_PACKAGE_T
 *
 */
typedef struct bc_symbol_list
{
  bc_symbol_t            symbol;
  struct bc_symbol_list *next;
} *bc_symbol_list_t;

typedef struct bc_package
{
  /* Name of the package */
  bc_string_t      name;

  /* List of symbols in the package */
  bc_symbol_list_t symbols;

  /* Link to next package */
  struct bc_package *next;

} *bc_package_t;

#define BC_PACKAGE_NAME( package )    ((package)->name)
#define BC_PACKAGE_SYMBOLS( package ) ((package)->symbols)
#define BC_PACKAGE_NEXT( package )    ((package)->next)

extern bc_package_t bc_package_list;
extern bc_package_t bc_current_package;
extern bc_package_t bc_function_package;

extern bc_symbol_t
package_find_symbol (bc_package_t package,
		     bc_string_t  name);

extern bc_symbol_t
package_intern_symbol (bc_package_t package,
		       bc_string_t  name);

#if defined (NEVER_DEFINED)
/*
 * BC_VARIABLE_T (what)
 *
 * Things that are read/parsed but for which we can't commit to 
 * a particular representation.  For example:
 *   <add 1.0000 2.0000>
 *      => "3.00"
 *      => "1.0000+2.0000"
 *      => "1.0000 is a variable bound to this; 2.0000 is ignored"
 * depending on the definition of 'add'.  Clearly if the numbers were
 * parsed and passed as numbers then the second definition for 'add'
 * could never be achieved.
 *
 * I think only symbols, strings, and numbers could possibly be read
 * into their internal representation and thus we need to keep around
 * the original 
 *
 * Remember: TYPE ERRORS produce NO OUTPUT */
typedef struct bc_variable
{
  bc_string_t string;
  bc_type_t   type;
  union
  {
    bc_number_t number;
    bc_symbol_t symbol;
    /* bc_string_t is above */
  } u;
} *bc_variable_t;

#endif /* NEVER_DEFINED */

/*
 * BC_STREAM_T
 *
 */
typedef struct bc_stream
{
  FILE *file;
} *bc_stream_t;

#define BC_STREAM_FILE( stream )     ((stream)->file)

/*
 * BC_FUNCTION_T
 *
 * Functions are very simple because environment vectors are not
 * required; the 'code' is the function
 *
 */
typedef struct bc_function {
  bc_string_t     name;		/* redundant (mostly) */
  bc_byte_code_t *code;		/* Vector of BYTEOPS */
  unsigned int    code_count;	/* Number of BYTEOPS in code */

  struct bc_tagged_object *constants;	/* Vector of CONSTANTS */
  unsigned int    constants_count;	/* Number of CONSTANTS in constants */
  unsigned int    stack_size;		/* Required STACK SIZE */
} *bc_function_t;

#define BC_FUNCTION_NAME( function )            ((function)->name)
#define BC_FUNCTION_CODE( function )            ((function)->code)
#define BC_FUNCTION_CODE_COUNT( function )      ((function)->code_count)
#define BC_FUNCTION_CONSTANTS( function )       ((function)->constants)
#define BC_FUNCTION_CONSTANTS_COUNT( function ) ((function)->constants_count)
#define BC_FUNCTION_STACK_SIZE( function )      ((function)->stack_size)

extern bc_function_t
bc_function_new (bc_string_t     name,
		 bc_byte_code_t *code,
		 unsigned int    code_count,
		 struct bc_tagged_object *constants,
		 unsigned int    constants_count,
		 unsigned int    stack_size);

extern void
bc_function_free (bc_function_t function);


/*
 *
 * BC_MACRO_T, BC_SPECIAL_FORM_T, BC_HTML_T
 *   (see expand.c)
 *
 */
typedef struct bc_macro        *bc_macro_t;
typedef struct bc_special_form *bc_special_form_t;
typedef struct bc_html         *bc_html_t;


#if defined (PREFER_CALL_BY_VALUE_WHICH_WE_DONT)

struct bc_object
{
  bc_object_type_t type;

  bc_string_t      name;

  union
  {
    bc_string_t   string;
    bc_number_t   number;
    bc_symbol_t   symbol;
    bc_package_t  package;
    bc_stream_t   stream; 
    bc_array_t    array;
    bc_function_t function;
    bc_macro_t    macro;
  } u;
};

#define BC_OBJECT_TYPE( object )         ((object)->type)

#define BC_OBJECT_AS_STRING( object )    ((object)->u.string)
#define BC_OBJECT_AS_NUMBER( object )    ((object)->u.number)
#define BC_OBJECT_AS_SYMBOL( object )    ((object)->u.symbol)
#define BC_OBJECT_AS_PACKAGE( object )   ((object)->u.package)
#define BC_OBJECT_AS_STREAM( object )    ((object)->u.stream)
#define BC_OBJECT_AS_ARRAY( object )     ((object)->u.array)
#define BC_OBJECT_AS_FUNCTION( object )  ((object)->u.function)
#define BC_OBJECT_AS_MACRO( object )     ((object)->u.macro)

/* Perhaps each arguments is passed in one of these containers.  Then if the 
   tag is not bound to a function, then the name can be used for output.
   Maybe this is not needed and the bc_string_t in bc_object_t does
   the same?  Don't think so.

   Readable_object is required to ensure that what is read and parsed
   is not lost when it's display is required.  Most notably, symbol
   FOO can be read as foo, FOO, Foo, etc and when printed it must be
   displayed as read. */
typedef struct bc_named_object
{
  bc_string_t name;
  union {
    bc_number_t number;
    bc_string_t string;
    bc_symbol_t symbol;
    bc_char_t   char;
  } u;
  /* bc_object_t object; */
} *bc_named_object_t, bc_readable_object_t;

#endif /* PREFER_CALL_BY_VALUE_WHICH_WE_DONT */

#endif /* ! _BC_OBJECT_H_ */
