#include "string.h"
#include "Cons.h"
#include "Nil.h"
#include "defs.h"
#include "SchemeString.h"

Cons *cons (SchemeObject *car, SchemeObject *cdr)
{
    return [Cons newWithCar: car cdr: cdr];
}

int length (SchemeObject *foo)
{
    local int len;

    for (len = 0; [foo isKindOfClass: [Cons class]]; foo = [(Cons *) foo cdr]) {
            len++;
    }

    return len;
}

BOOL isList (SchemeObject *ls)
{
    return ls == [Nil nil] ||
        ([ls isKindOfClass: [Cons class]] &&
         isList([(Cons*) ls cdr]));
}

@implementation Cons

+ (id) newWithCar: (SchemeObject *) a cdr: (SchemeObject *) d
{
    return [[self alloc] initWithCar: a cdr: d];
}

- (id) initWithCar: (SchemeObject *) a cdr: (SchemeObject *) d
{
    car = a;
    cdr = d;

    if (!car) {
            print("Cons: WARNING: nil car\n");
    } else if (!cdr) {
            print("cons: WARNING: nil cdr\n");
    }

     return [super init];
}

- (SchemeObject *) car
{
    return car;
}

- (void) car: (SchemeObject *) a
{
    car = a;
}

- (SchemeObject *) cdr
{
    return cdr;
}

- (void) cdr: (SchemeObject *) d
{
    cdr = d;
}   

- (void) markReachable
{
    [car mark];
    [cdr mark];
}

- (string) printForm
{
    local string acc = "";
    local id cur, next = nil;

    for (cur = self; cur; cur = next) {
            next = [cur cdr];
            acc = acc + [[cur car] printForm];
            if (next == [Nil nil]) {
                    next = nil;
            } else  if (next && ![next isKindOfClass: [Cons class]]) {
                    acc = acc + " . " + [next printForm];
                    next = nil;
            } else if (next) {
                    acc = acc + " ";
            }
    }

    return [[String newFromString: sprintf("(%s)", acc)] stringValue];
}

@end
