#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>


#define MARKABLE(_item) \
 ((_item)!=nil && ((id)(_item))!=(id)[NSNull null] && \
  [(_item) isKindOfClass:[SCMType class]])

@interface SCMType : NSObject
{
@protected
    int mark;
}

+ (int)allocatedAfterGC;
+ (int)totalAllocated;
+ (int)nextMark;

+ runGC;

+ alloc;


+ addToMarkables:(id)item;
+ removeFromMarkables:(id)item;
+ currentMarkForMarkables;

- (int)mark;
- setMark:(int)newMark;
- setMarkToCurrent;

- (void)free;
@end

// type name fix by Matt Rice
@interface Boolean : SCMType
{
    BOOL value;
}

- initSCMBoolean:(BOOL)val;
- (BOOL)boolVal;

@end

@interface Char : SCMType
{
    char value;
}


- initSCMChar:(char)val;
- (char)charVal;

@end

@interface Int : SCMType
{
    long int value;
}


- initSCMInt:(long int)val;
- (long int)intVal;
- (double)doubleVal;

@end

@interface Double : SCMType
{
    double value;
}


- initSCMDouble:(double)val;
- (double)doubleVal;

@end

@interface Symbol : SCMType
{
    NSString *value;
}

- initSCMSymbol:(char *)val;
- (NSString *)symVal;

- (void)free;
@end

@interface String : SCMType
{
    NSString *value;
}

- initSCMStringLEX:(char *)val;
- initSCMString:(char *)val;
- (NSString *)strVal;

- (void)free;
@end

@interface Pair : SCMType
{
    id car;
    id cdr;
}

+ (int)length:(Pair *)list;

+ newCar:(id)carval Cdr:(id)cdrval;
- initCar:(id)carval Cdr:(id)cdrval;

- car;
- cdr;

- setcar:(id)carval;
- setcdr:(id)cdrval;

- setMarkToCurrent;

@end

@interface Vector : SCMType
{
    id *data;
    unsigned count;
}

+ newFromList:(Pair *)list;
+ newWithItem:(id)item count:(int)cval;

- initWithList:(Pair *)list;
- initWithItem:(id)item count:(int)cval;

- (id *)entries;
- (unsigned)count;

- setMarkToCurrent;

- (void)free;

@end


@interface Closure : SCMType
{
    id args;
    id body;
    id env;
}

+ newArgs:(id)argsval Body:(id)codes Env:(id)envval;
- initArgs:(id)argsval Body:(id)codes Env:(id)envval;

- args;
- body;
- env;

- setMarkToCurrent;

@end

@interface Thunk : SCMType
{
    int argp;
    int envp;
    int codep;
}

+ newArgp:(int)argpval Envp:(int)envpval Codep:(int)codepval;

- initArgp:(int)argpval Envp:(int)envpval Codep:(int)codepval;

- (int)argp;
- setArgp:(int)argpval;

- (int)envp;
- setEnvp:(int)envpval;

- (int)codep;
- setCodep:(int)envpval;

@end

@interface Environment : SCMType
{
    Environment *parent;
    NSMapTable *data;
}

+ newParent:(Environment *)par Data:(NSMapTable *)entries;
- initParent:(Environment *)par Data:(NSMapTable *)entries;

- (int)chainLength;

- (NSMapTable *)lookup:(NSString *)sym;

- (Environment *)parent;
- (NSMapTable *)data;

- setMarkToCurrent;

- (void)free;

@end

typedef enum {
    FORM_TOP = 0,
    FORM_DEFINE1,
    FORM_DEFINE2,
    FORM_SET,
    FORM_LAMBDA1,
    FORM_LAMBDA2,
    FORM_QUOTE,
    FORM_BINDING,
    FORM_LET,
    FORM_LETSTAR,
    FORM_LETREC,
    FORM_IF1,
    FORM_IF2,
    FORM_AND,
    FORM_OR,
    FORM_BEGIN,
    FORM_APPLY,
    FORM_CASE,
    FORM_SCOND1,
    FORM_SCOND2,
    FORM_SCOND3,
    FORM_COND,
    FORM_CALLCC
} FORMTYPE;

@interface Triple : SCMType
{
    int tag;
    id items[3];
}

+ newTag:(int)tagval;
+ newTag:(int)tagval IntArg1:(int)arg1;
+ newTag:(int)tagval Arg1:(id)arg1;
+ newTag:(int)tagval Arg1:(id)arg1 Arg2:(id)arg2;
+ newTag:(int)tagval Arg1:(id)arg1 Arg2:(id)arg2 Arg3:(id)arg3;

- initTag:(int)tagval Arg1:(id)arg1 Arg2:(id)arg2 Arg3:(id)arg3;

- (int)tag;
- (int)intarg1;
- setIntArg1:(int)val;

- arg1;
- arg2;
- arg3;

- setMarkToCurrent;

@end


typedef enum {
    IN_TO_ARGS = 0,
    IN_LOOKUP,
    IN_CHECK_PTC,
    IN_POP_ENV,
    IN_POP_ARGS,
    IN_APPLIC,
    IN_LIST_APPLIC,
    IN_DEFINE,
    IN_SET,
    IN_CLOSURE,
    IN_IF,
    IN_LAYER,
    IN_MEMQ,
    IN_DUP_ARG,
    IN_EXCH_ARGS,
    IN_STATE_TO_THUNK,
    IN_MARK_THUNK,
    INSTR_COUNT
} INSTRUCTION;

@interface ByteCodes : SCMType
{
    unsigned int capacity;
    unsigned int length;
    id *data;

    BOOL root;
    id source;
}

+ new;
- init;


- prependTriple:(Triple *)theTriple;
- addTriple:(Triple *)theTriple;

- appendByteCodes:(ByteCodes *)codes;

- (id *)codes;
- (unsigned int)length;

- setMarkToCurrent;

- (BOOL)root;
- setRoot:(BOOL)rflag;

- source;
- setSource:(id)src;

- (void)free;

@end

