#ifndef __SCHEME_ITEM_H__
#define __SCHEME_ITEM_H__

typedef enum {
    INT_TYPE, REAL_TYPE, STR_TYPE, CONS_TYPE, NULL_TYPE, PTR_TYPE,
    OPEN_TYPE, CLOSE_TYPE, BOOL_TYPE, SYMBOL_TYPE, SINGLEQUOTE_TYPE,
    VOID_TYPE, CLOSURE_TYPE,

    // Types below are only for bonus work
    DOT_TYPE, OPENBRACKET_TYPE, CLOSEBRACKET_TYPE
} item_type_t;

// Forward declaration to make cyclical scheme_item_t def work
typedef struct Frame frame_t;

typedef struct scheme_item_t {
    item_type_t type;
    union {
        int i;
        double r;
        char *s;
        struct {
            struct scheme_item_t *car;
            struct scheme_item_t *cdr;
        }; // For CONS_TYPE
        struct {
            struct scheme_item_t *paramNames;
            struct scheme_item_t *functionCode;
            frame_t *frame;
        }; // For CLOSURE_TYPE
        void *ptr;
    };
} scheme_item_t;
// Where do you store a BOOL_TYPE boolean in the union? I recommend the int i
// (0 for false, 1 for true).

// A frame is a linked list of bindings, and a pointer to another frame.  A
// binding is a variable name (represented as a string), and a pointer to the
// object it is bound to.  Specifically how you implement the list of bindings
// is up to you.
typedef struct Frame {
    struct Frame *parent;
    scheme_item_t *bindings;
} frame_t;

#endif // __SCHEME_ITEM_H__
