/*
 * This header provides an interface between a generated code and the
 * runtime system.
 */

# ifndef CXGR_COMMON_H
# define CXGR_COMMON_H

/* # include <stdint.h> */

/*
 * cxgr_word type
 *
 * The memory spaces are viewed as arrays of cxgr_word objects.
 * The runtime system always operates on words, not on bytes or
 * halfwords.
 *
 * cxgr_word must be an unsigned integer type that is large enough to
 * store a void pointer.
 */

/* typedef uintptr_t cxgr_word; */
typedef unsigned long cxgr_word;

/*
 * Active memory space
 *
 * An active memory space is a contiguous array of cxgr_word objects,
 * containing the allocation area and the stack space.
 * Two pointers named hp and sp points onto the array, and a
 * invariance "hp <= sp" holds.
 * hp and sp indicates the end of the allocation area and the
 * beginning of the stack, respectively.
 *
 * <-LOW------------------------------------------------HIGH->
 *    allocation area       | freespace |   stack
 * -----------------------------------------------------------
 *                          ^           ^
 *                          hp          sp
 */

typedef struct
{
  cxgr_word *hp;
  cxgr_word *sp;
} cxgr_space;

typedef struct cxgr_runtime_info_struct cxgr_runtime_info;

/*
 * Object layout
 *
 * An object is an array of 3 or more cxgr_words. The layout is as
 * follows.
 *
 * head: a nonzero integer.
 * k: an integer.
 * n: an integer. (invariant: k <= n)
 * body: an array of (n-k) values.
 *
 * A value is a cxgr_word, containing one of the following:
 *
 * (a) A pointer to an object in the heap.
 * (b) A pointer to somewhere outside the heap.
 * (c) An odd number.
 *
 * Of these, only (a) is modified during a GC. Therefore you cannot
 * safely maintain a pointer into the stack as a value.
 *
 * The stack is an array of values, and the heap contains objects.
 * The heap includes the allocation area, but there may be other heap
 * areas as well. You cannot directly allocate objects there, but a
 * GC may place an object there.
 */

/* Functions provided by a generated code */

/* Exit status of the generated code */
typedef enum
{
  cxgr_success, /* The program terminated successfully */
  cxgr_error_out_notchar, /* The primitive Out was called with an argument that is not a character */
  cxgr_error_succ_notchar, /* Similar but the primitive Succ was used */
  cxgr_error_stack_oob, /* An out-of-bound Grass stack refererence was made */
  cxgr_error_internal /* An error ocurred because of a compiler bug */
} cxgr_status;

typedef struct
{
  cxgr_status status;
  cxgr_word *sp;
  cxgr_word *hp;
} cxgr_result;

/*
 * The entry point of the code.
 *
 * sp: initial sp
 * hp: initial hp
 * statics: a pointer to an array, which is to be used to hold static
 *   values. Initially it is filled with arbitrary odd numbers.
 * info: extra information managed by the runtime system
 */
cxgr_result cxgr_code(cxgr_word *sp, cxgr_word *hp, cxgr_word *statics, cxgr_runtime_info *info);
/* returns how many static objects the program will use. */
int cxgr_static_count(void);

/*
 * Functions provided by the runtime system 
 *
 * These functions are to be called by cxgr_code.
 * They may or may not be return. If they do not return, they longjmp
 * directly to a caller of cxgr_code.
 */

/*
 * Performs GC.
 *
 * sp: the current sp
 * hp: the current hp
 * request: the minimum number of elements that must be available
 *   between sp and hp, after the function returns.
 *
 * During a GC, the active memory space will be moved and may be
 * resized, but the static object array will not be moved.
 * The function returns a pair consisting of the new sp and hp.
 */
cxgr_space cxgr_gc(cxgr_word *sp, cxgr_word *hp, int request, cxgr_runtime_info *);

/*
 * Output a character to stdout, without buffering.
 *
 * c: a encoded character. A character of ASCII code x will be
 *   represented by a odd number (2*x+1).
 */
void cxgr_putchar(cxgr_word c);

/*
 * Read a character from stdin, and returns it encoded in the same
 * manner as cxgr_putchar.
 * On EOF, it returns CXGR_EOF.
 */
cxgr_word cxgr_getchar(void);
# define CXGR_EOF 0xffff

/*
 * Show a message to the user.
 */
void cxgr_message(const char *msg, cxgr_runtime_info *);

# endif
