#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <iso646.h>
#include <clang-c/Index.h>

// Viva Greenspun's Tenth Law!


typedef enum {false=0,true=1} bool;

#define INCF(X) (++(X))
#define DECF(X) (--(X))
#define CONCAT_INTERN(A,B) A##B
#define CONCAT(A,B) CONCAT_INTERN(A,B)
#define PUSH(ELEMENT,LIST_PLACE) \
    ({ (LIST_PLACE)=cons((ELEMENT),(LIST_PLACE)); })
#define POP_INTERN(RESVAR,LIST_PLACE) \
    ({ id RESVAR=car(LIST_PLACE); (LIST_PLACE)=cdr(LIST_PLACE); RESVAR; })
#define POP(LIST_PLACE) \
    POP_INTERN(CONCAT(result_,__LINE__),LIST_PLACE)

#define PUSH2(k,v,plist) ({PUSH(v,plist);PUSH(k,plist);})




void signal_error(const char* file,int line,const char* function,const char* message,...){
    fprintf(stderr,"\n%s:%d:1: error in %s: ",file,line,function);
    va_list ap;
    va_start(ap,message);
    vfprintf(stderr,message,ap);
    va_end(ap);
    fprintf(stderr,"\n");
    fflush(stderr);}


#define ERROR_INTERNAL(MESSAGE,...)                      \
    do{                                                                     \
        signal_error(__FILE__,__LINE__,__FUNCTION__,MESSAGE,##__VA_ARGS__); \
        exit(1);                                                            \
    }while(0)
#define ERROR(MESSAGE,...)                                              \
    ERROR_INTERNAL(MESSAGE,##__VA_ARGS__)

#define ASSERT_INTERNAL(EXPRESSION)                                     \
    do{                                                                 \
        if(!(EXPRESSION)){                                              \
            fflush(stdout);                                             \
            signal_error(__FILE__,__LINE__,__FUNCTION__,                \
                         "assertion failed: %s",#EXPRESSION);           \
            exit(1);                                                    \
        }                                                               \
    }while(0)

#define UNLESS_ASSERT_INTERNAL(EXPRESSION,BODY)                         \
    do{                                                                 \
        if(!(EXPRESSION)){                                              \
            fflush(stdout);                                             \
            signal_error(__FILE__,__LINE__,__FUNCTION__,                \
                         "assertion failed: %s",#EXPRESSION);           \
            { BODY }                                                    \
              fflush(stderr);                                           \
              exit(1);                                                  \
        }                                                               \
    }while(0)


#define assert(EXPRESSION) ASSERT_INTERNAL(EXPRESSION)
#define unless_assert(EXPRESSION,BODY) UNLESS_ASSERT_INTERNAL(EXPRESSION,BODY)
#define ASSERT(EXPRESSION,MESSAGE,...) UNLESS_ASSERT_INTERNAL(EXPRESSION,{fprintf(stderr,MESSAGE,##__VA_ARGS__);})




int imax(int a,int b){
    return((a<b)?b:a);}

int imin(int a,int b){
    return((a<b)?a:b);}


void* memory_allocate(const char* fname,int element_size,int element_count){
    // /*DEBUG*/printf("%s(%s,%d)\n",__FUNCTION__,fname,size); fflush(stdout);
    void* memory=malloc(imax(0,element_size*element_count));
    if(0==memory){
        fprintf(stderr,"%s: out of memory\n",fname);
        exit(1);}
    return(memory);}





typedef enum {
    ot_nil=0,
    ot_t,
    ot_object=ot_t,
    ot_CXCursor,    // CXCursor*
    ot_int,         // int
    ot_char,        // char
    ot_cons,        // cons*
    ot_vector,      // vector*
    ot_hashtable,   // hashtable*
} object_type;

const char* type_name(object_type type){
    switch(type){
      case ot_nil:       return("nil");
      case ot_t:         return("t");
      case ot_CXCursor:  return("CXCursor");
      case ot_int:       return("integer");
      case ot_char:      return("character");
      case ot_cons:      return("cons");
      case ot_vector:    return("vector");
      case ot_hashtable: return("hashtable");
      default:           ASSERT(false,"Unknown type %d",type);}}

int type_size(object_type type){
    switch(type){
      case ot_nil:       return(0);
      case ot_t:         return(sizeof(struct object*));
      case ot_CXCursor:  return(sizeof(CXCursor));
      case ot_int:       return(sizeof(int));
      case ot_char:      return(sizeof(char));
      case ot_cons:      return(sizeof(struct cons*));
      case ot_vector:    return(sizeof(struct vector*));
      case ot_hashtable: return(sizeof(struct hashtable*));
      default:           ASSERT(false,"Unknown type %d",type);}}





typedef struct object {
    object_type type;
    union {
        CXCursor cursor;
        int integer;
        char character;
        struct cons* cons;
        struct vector* vector;
        struct hashtable* hashtable;
    } value;
} object;

typedef object* id;


void* nil=0;

bool null(void* object){
    return(0==object);}

static object t_object={ot_t};
id t=&t_object;

id boolean(int value){
    return(value?t:nil);}


object_type type_of(id object){
    assert(nil!=object);
    return(object->type);}

id box(object_type type,...){
    id o=memory_allocate(__FUNCTION__,sizeof(*o),1);
    o->type=type;
    va_list ap;
    va_start(ap,type);
    switch(type){
      case ot_CXCursor:  o->value.cursor=(va_arg(ap,CXCursor));             break;
      case ot_int:       o->value.integer=va_arg(ap,int);                   break;
      case ot_char:      o->value.character=va_arg(ap,int);                 break;
      case ot_cons:      o->value.cons=va_arg(ap,struct cons*);             break;
      case ot_vector:    o->value.vector=va_arg(ap,struct vector*);         break;
      case ot_hashtable: o->value.hashtable=va_arg(ap,struct hashtable*);   break;
      default: ERROR("unexpected object type %s.",type_name(type));         break;}
    va_end(ap);
    return(o);}


id cursorp(id x){
    return(boolean(not(null(x)) and (ot_CXCursor==type_of(x))));}

id cursor(CXCursor value){
    return(box(ot_CXCursor,value));}

CXCursor unbox_cursor(id o){
    assert(nil!=o);
    assert(ot_CXCursor==type_of(o));
    return(o->value.cursor);}


id integerp(id x){
    return(boolean(not(null(x)) and (ot_int==type_of(x))));}

id integer(int value){
    return(box(ot_int,value));}

int unbox_integer(id o){
    assert(nil!=o);
    assert(ot_int==type_of(o));
    return(o->value.integer);}

id zerop(id object){
    return(boolean(integerp(object) and (0==unbox_integer(object))));}

id plusp(id object){
    return(boolean(integerp(object) and (0<unbox_integer(object))));}

id minusp(id object){
    return(boolean(integerp(object) and (0>unbox_integer(object))));}




id characterp(id x){
    return(boolean(not(null(x)) and (ot_char==type_of(x))));}

id character(char value){
    return(box(ot_char,value));}

char unbox_character(id o){
    assert(nil!=o);
    assert(ot_char==type_of(o));
    return(o->value.character);}



typedef struct cons {
    id car;
    id cdr;
} cons_t;

cons_t* make_cons_t(id a,id d){
    cons_t* cell=memory_allocate(__FUNCTION__,sizeof(*cell),1);
    cell->car=a;
    cell->cdr=d;
    return(cell);}

id consp(id a){
    return(boolean(not(null(a)) and (ot_cons==type_of(a))));}

cons_t* unbox_cons(id o){
    assert(nil!=o);
    assert(ot_cons==type_of(o));
    return(o->value.cons);}

id cons(id a,id d){
    return(box(ot_cons,make_cons_t(a,d)));}

id car(id cell){
    if(null(cell)){ return(cell); }
    else if(ot_cons==type_of(cell)){ return(cell->value.cons->car); }
    else{ ERROR("Expected argument of type LIST, not %s",
                type_name(type_of(cell))); return(nil); }}

id cdr(id cell){
    if(null(cell)){ return(cell); }
    else if(ot_cons==type_of(cell)){ return(cell->value.cons->cdr); }
    else{ ERROR("Expected argument of type LIST, not %s",
                type_name(type_of(cell))); return(nil); }}

id setcar(id cell,id a){
    if(cell and (ot_cons==type_of(cell))){ cell->value.cons->car=a; return(a); }
    else{ ERROR("Expected argument of type CONS, not %s",
                type_name(type_of(cell))); return(nil); }}

id setcdr(id cell,id d){
    if(cell and (ot_cons==type_of(cell))){ cell->value.cons->cdr=d; return(d); }
    else{ ERROR("Expected argument of type CONS, not %s",
                type_name(type_of(cell))); return(nil); }}

id caar   (id cell){return(car(car(cell)));}
id cadr   (id cell){return(car(cdr(cell)));}
id cdar   (id cell){return(cdr(car(cell)));}
id cddr   (id cell){return(cdr(cdr(cell)));}

id caaar  (id cell){return(car(car(car(cell))));}
id cadar  (id cell){return(car(cdr(car(cell))));}
id cdaar  (id cell){return(cdr(car(car(cell))));}
id cddar  (id cell){return(cdr(cdr(car(cell))));}

id caadr  (id cell){return(car(car(cdr(cell))));}
id caddr  (id cell){return(car(cdr(cdr(cell))));}
id cdadr  (id cell){return(cdr(car(cdr(cell))));}
id cdddr  (id cell){return(cdr(cdr(cdr(cell))));}

id first  (id list){return(car(list));}
id rest   (id list){return(cdr(list));}
id second (id list){return(car(cdr(list)));}
id third  (id list){return(car(cdr(cdr(list))));}
id fourth (id list){return(car(cdr(cdr(cdr(list)))));}
id fifth  (id list){return(car(cdr(cdr(cdr(cdr(list))))));}
id sixth  (id list){return(car(cdr(cdr(cdr(cdr(cdr(list)))))));}
id seventh(id list){return(car(cdr(cdr(cdr(cdr(cdr(cdr(list))))))));}
id eighth (id list){return(car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(list)))))))));}
id nineth (id list){return(car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(list))))))))));}
id tenth  (id list){return(car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(cdr(list)))))))))));}

id last   (id list){
    while(cdr(list)){
        list=cdr(list);}
    return(list);}

id nth(int n,id list){
    while((0<n--) and list){
        list=cdr(list);}
    return(car(list));}

id nthcdr(int n,id list){
    while((0<--n) and list){
        list=cdr(list);}
    return(list);}


int list_length(id list){
    int n=0;
    while(consp(list)){
        list=cdr(list);
        n++;}
    return(n);}

id list(int n,...){
    switch(n){
      case 0:
          return(nil);
      default:{
          va_list ap;
          va_start(ap,n);
          id result=cons(va_arg(ap,id),nil);
          id tail=result;
          for(int i=1;i<n;i++){
              setcdr(tail,cons(va_arg(ap,id),nil));
              tail=cdr(tail);}
          va_end(ap);
          return(result);}}}

id prepend(int n,...){
    // list*
    switch(n){
      case 0:
          return(nil);
      case 1:{
          va_list ap;
          va_start(ap,n);
          id result=va_arg(ap,id);
          va_end(ap);
          return(result);}
      default:{
          va_list ap;
          va_start(ap,n);
          id result=cons(va_arg(ap,id),nil);
          id tail=result;
          for(int i=2;i<n;i++){
              setcdr(tail,cons(va_arg(ap,id),nil));
              tail=cdr(tail);}
          va_end(ap);
          setcdr(tail,va_arg(ap,id));
          return(result);}}}

id reverse_accumulator(id list,id reversed){
    return(null(list)
           ?reversed
           :reverse_accumulator(cdr(list),cons(car(list),reversed)));}

id reverse(id list){
    return(reverse_accumulator(list,nil));}

id revappend(id list,id tail){
    return(reverse_accumulator(list,tail));}

id nreconc(id list,id tail){
    while(not(null(list))){
        id next=cdr(list);
        setcdr(list,tail);
        tail=list;
        list=next;}
    return(tail);}

id nreverse(id list){
    return(nreconc(list,nil));}

id copy_list(id list){
    if(null(list)){
        return(nil);
    }else{
        id result=cons(car(list),nil);
        id tail=result;
        list=cdr(list);
        while(not(null(list))){
            setcdr(tail,cons(car(list),nil));
            tail=cdr(tail);
            list=cdr(list);}
        return(result);}}

id append(int n,...){
    switch(n){
      case 0: return(nil);
      case 1:{
          va_list ap;
          va_start(ap,n);
          id result=va_arg(ap,id);
          va_end(ap);
          return(result);}
      default:{
          va_list ap;
          va_start(ap,n);
          id result=cons(nil,nil);
          id tail=result;
          for(int i=1;i<n;i++){
              setcdr(tail,copy_list(va_arg(ap,id)));
              tail=last(tail);}
          setcdr(tail,va_arg(ap,id));
          va_end(ap);
          return(cdr(result));}}}


typedef struct vector {
    object_type element_type;
    int size;
    int fill_pointer;
    char* data;
} vector_t;

id vectorp(id x){
    return(boolean(not(null(x)) and (ot_vector==type_of(x))));}

vector_t* unbox_vector(id o){
    assert(nil!=o);
    assert(ot_vector==type_of(o));
    return(o->value.vector);}

vector_t* vector_set_data(vector_t* v,int index,const void* data);

id make_vector(object_type element_type,int size,int fill_pointer,const void* initial_element){
    int element_size=type_size(element_type);
    assert(0<element_size);
    assert(0<=size);
    assert(0<=fill_pointer);
    assert(fill_pointer<=size);
    vector_t* v=memory_allocate(__FUNCTION__,sizeof(*v),1);
    v->data=memory_allocate(__FUNCTION__,element_size,size);
    v->element_type=element_type;
    v->size=size;
    v->fill_pointer=fill_pointer;
    if(0!=initial_element){
        for(int i=0;i<size;i++){
            vector_set_data(v,i,initial_element);}}
    return(box(ot_vector,v));}

object_type vector_element_type(id vect){
    vector_t* v=unbox_vector(vect);
    return(v->element_type);}

int vector_size(id vect){
    vector_t* v=unbox_vector(vect);
    return(v->size);}

int vector_fill_pointer(id vect){
    vector_t* v=unbox_vector(vect);
    return(v->fill_pointer);}

id vector_set_fill_pointer(id vect,int fill_pointer){
    vector_t* v=unbox_vector(vect);
    assert(0<=fill_pointer);
    assert(fill_pointer<=v->size);
    v->fill_pointer=fill_pointer;
    return(vect);}

int vector_length(id vect){
    return(vector_fill_pointer(vect));}


vector_t* vector_set_data(vector_t* v,int index,const void* data){
    assert(nil!=v);
    assert(0<=index);
    assert(index<v->size);
    int element_size=type_size(v->element_type);
    char* slot=v->data+element_size*index;
    memcpy(slot,data,element_size);
    return(v);}

id vector_set_char(id vect,int index,char data){
    vector_t* v=unbox_vector(vect);
    assert(ot_char==v->element_type);
    vector_set_data(v,index,&data);
    return(vect);}

id vector_set_int(id vect,int index,int data){
    vector_t* v=unbox_vector(vect);
    assert(ot_int==v->element_type);
    vector_set_data(v,index,&data);
    return(vect);}

id vector_set(id vect,int index,id object){
    vector_t* v=unbox_vector(vect);
    switch(v->element_type){
      case ot_t:
          vector_set_data(v,index,&object);
          break;
      case ot_int:
          if(ot_int==type_of(object)){
              int value=unbox_integer(object);
              vector_set_data(v,index,&value);
          }else{
              ERROR("Trying to store a non-integer into a (VECTOR INTEGER).");
          }
          break;
      case ot_char:
          if(ot_char==type_of(object)){
              char value=unbox_character(object);
              vector_set_data(v,index,&value);
          }else{
              ERROR("Trying to store a non-character into a STRING.");
          }
          break;
      default:
          ERROR("Unexpected vector element type %s.",type_name(v->element_type));
          break;
    }
    return(vect);}

id vector(int n,...){
    switch(n){
      case 0:
          return(make_vector(ot_t,0,0,0));
      default:{
          id v=make_vector(ot_t,n,n,0);
          va_list ap;
          va_start(ap,n);
          for(int i=0;i<n;i++){
              vector_set(v,i,va_arg(ap,id));}
          va_end(ap);
          return(v);}}}

void* vector_get_data(vector_t* v,int index){
    assert(nil!=v);
    assert(0<=index);
    assert(index<v->size);
    return(v->data+type_size(v->element_type)*index);}

char vector_get_char(id vect,int index){
    vector_t* v=unbox_vector(vect);
    assert(ot_char==v->element_type);
    char result;
    memcpy(&result,vector_get_data(v,index),sizeof(char));
    return(result);}

int vector_get_int(id vect,int index){
    vector_t* v=unbox_vector(vect);
    assert(ot_int==v->element_type);
    int result;
    memcpy(&result,vector_get_data(v,index),sizeof(int));
    return(result);}

id vector_get(id vect,int index){
    vector_t* v=unbox_vector(vect);
    id result=0;
    switch(v->element_type){
      case ot_t:
          memcpy(&result,vector_get_data(v,index),sizeof(id));
          break;
      case ot_int:
          result=integer(*(int*)vector_get_data(v,index));
          break;
      case ot_char:
          result=character(*(char*)vector_get_data(v,index));
          break;
      default:
          ERROR("Unexpected vector element type %s.",type_name(v->element_type));
          break;
    }
    return(result);}


id stringp(id x){
    return(boolean(not(null(x))
                   and (ot_vector==type_of(x))
                   and (ot_char==vector_element_type(x))));}

id string(const char* text){
    int len=strlen(text);
    id vect=make_vector(ot_char,len,len,0);
    memcpy(vect->value.vector->data,text,len);
    return(vect);}

const char* unbox_string(id string){
    assert(stringp(string));
    return(vector_get_data(unbox_vector(string),0));}

bool string_equal(vector_t* a,vector_t* b){
    if((a->element_type!=b->element_type)
       or (ot_char!=a->element_type)
       or (a->fill_pointer!=b->fill_pointer)){
        return(false);
    }
    return(0==memcmp(a->data,b->data,a->fill_pointer));}

unsigned string_hash(vector_t* s){
    // djb2 (k=33)
    assert(nil!=s);
    assert(ot_char==s->element_type);
    int count=s->fill_pointer;
    const char* bytes=s->data;
    unsigned hash=5381;
    int c;
    while((c=*bytes++)){
        hash=((hash<<5)+hash)^c;}
    return(hash);}




int length(id object){
    if(null(object)){
        return(0);
    }else if(consp(object)){
        return(list_length(object));
    }else if(vectorp(object)){
        return(vector_length(object));
    }else{
        ERROR("Expected object of type SEQUENCE, not %s.",type_name(type_of(object)));
        return(0);}}


id equal(id a,id b){
    if(a==b){
        return(t);
    }else if(a->type==b->type){
        switch(a->type){
          case ot_nil:       return(t);
          case ot_CXCursor:  return(boolean(clang_equalCursors(a->value.cursor,b->value.cursor)));
          case ot_int:       return(boolean(a->value.integer==b->value.integer));
          case ot_char:      return(boolean(a->value.character==b->value.character));
          case ot_cons:      return(boolean(equal(car(a),car(b)) and equal(cdr(a),cdr(b))));
          case ot_vector:    return(boolean((a->value.vector==b->value.vector)
                                            or ((ot_char==a->value.vector->element_type))
                                                and (ot_char==b->value.vector->element_type)
                                                and string_equal(a->value.vector,b->value.vector)));
          case ot_hashtable: return(boolean(a->value.hashtable==b->value.hashtable));
          default: assert(!"Unexpected type in an object."); return(nil); }
    }else{
        return(nil);}}



typedef struct hashtable {
    int count;
    int size;
    float rehash_size;
    float rehash_threshold;
    id* entries;
} hashtable;

id hashtablep(id x){
    return(boolean(not(null(x)) and (ot_hashtable==type_of(x))));}

hashtable* unbox_hashtable(id o){
    assert(nil!=o);
    assert(ot_hashtable==type_of(o));
    return(o->value.hashtable);}

int hashtable_count(id table){
    hashtable* h=unbox_hashtable(table);
    return(h->count);}

int hashtable_size(id table){
    hashtable* h=unbox_hashtable(table);
    return(h->size);}

float hashtable_rehash_size(id table){
    hashtable* h=unbox_hashtable(table);
    return(h->rehash_size);}

float hashtable_rehash_threshold(id table){
    hashtable* h=unbox_hashtable(table);
    return(h->rehash_threshold);}


unsigned hashtable_hash(hashtable*);

unsigned sxhash(id o){
    switch(o->type){
      case ot_nil:       return(0);
      case ot_CXCursor:  return(clang_hashCursor(o->value.cursor));
      case ot_int:       return(o->value.integer);
      case ot_char:      return(o->value.character);
      case ot_cons:      return(sxhash(car(o))+(sxhash(cdr(o))<<1));
      case ot_vector:    return((ot_char==o->value.vector->element_type)
                                ?string_hash(o->value.vector)
                                :(unsigned)(o->value.vector));
      case ot_hashtable: return((unsigned)(o->value.hashtable));
      case ot_t:         assert(!"Invalid object"); return(0); }}


int ceiling_to_nearest_prime(int n);
bool primep(int n);

id hashtable_deleted_entry=0;
bool hashtable_entry_deleted_p(id entry){
    return(hashtable_deleted_entry==entry);}

id make_hashtable(int size){
    if(null(hashtable_deleted_entry)){
        hashtable_deleted_entry=cons(nil,nil);}
    hashtable* h=memory_allocate(__FUNCTION__,sizeof(*h),1);
    h->count=0;
    h->size=primep(size)?size:ceiling_to_nearest_prime(1+size);
    h->rehash_size=2.0;
    h->rehash_threshold=1.5;
    h->entries=memory_allocate(__FUNCTION__,sizeof(*(h->entries)),h->size);
    int i=0;
    for(i=0;i<h->size;i++){
        h->entries[i]=nil;}
    return(box(ot_hashtable,h));}

unsigned hashtable_hash(hashtable* table){
    return((table->size<<3)+table->count);}


id hashtable_get(id table,id key){
    hashtable* h=unbox_hashtable(table);
    unsigned hash=sxhash(key);
    int i=hash%h->size;
    while(not(null(h->entries[i]))
          and not(equal(car(h->entries[i]),key))){
        i=(i+1)%h->size;}
    return(cdr(h->entries[i]));}

id hashtable_remove(id table,id key){
    hashtable* h=unbox_hashtable(table);
    unsigned hash=sxhash(key);
    int i=hash%h->size;
    while(not(null(h->entries[i]))
          and not(equal(car(h->entries[i]),key))){
        i=(i+1)%h->size;}
    id entry=h->entries[i];
    if(equal(car(entry),key)){
        DECF(h->count);
        h->entries[i]=hashtable_deleted_entry;
        return(cdr(entry));
    }else{
        return(nil);}}

typedef void(*hashtable_mapper_function)(id key,id value,void* data);

void hashtable_map(id table,hashtable_mapper_function fun,void* data){
    hashtable* h=unbox_hashtable(table);
    int size=h->size;
    id* entries=h->entries;
    for(int i=0;i<size;i++){
        id entry=entries[i];
        if(not(null(entry) or hashtable_entry_deleted_p(entry))){
            fun(car(entry),cdr(entry),data);}}}

void hashtable_statistics(id table){
    hashtable* h=unbox_hashtable(table);
    int runs=0;
    int minrun=0;
    int maxrun=0;
    int deleted=0;
    int maxdeleted=0;
    int mindeleted=0;

    id* entries=h->entries;

}

hashtable* hashtable_grow(hashtable* h){
    int newsize=ceiling_to_nearest_prime(h->size*h->rehash_threshold);
    id* newentries=memory_allocate(__FUNCTION__,sizeof(id),newsize);
    for(int j=0;j<newsize;j++){
        newentries[j]=nil;}
    for(int i=0;i<h->size;i++){
        id entry=h->entries[i];
        if(not(null(entry) or hashtable_entry_deleted_p(entry))){
            unsigned hash=sxhash(car(entry));
            int j=hash%newsize;
            while(not(null(newentries[j]))){
                j=(j+1)%newsize;}
            newentries[j]=entry;}}
    h->size=newsize;
    h->entries=newentries;
    return(h);}

id hashtable_set(id table,id key,id value){
    hashtable* h=unbox_hashtable(table);
    unsigned hash=sxhash(key);
    int i=hash%h->size;
    while(not(null(h->entries[i]))
          and not(equal(car(h->entries[i]),key))){
        i=(i+1)%h->size;}
    id entry=h->entries[i];
    if(null(entry) or hashtable_entry_deleted_p(entry)){
        if(h->size<=h->count*h->rehash_size){
            hashtable_grow(h);
            return(hashtable_set(table,key,value));
        }else{
            INCF(h->count);
            h->entries[i]=cons(key,value);
        }
    }else{
        setcdr(entry,value);
    }
    return(value);}


id compute_primes_to(int n){
    // /*DEBUG*/printf("%s(%d)\n",__FUNCTION__,n); fflush(stdout);
    const int zero=0;
    if(n<2){
        return(make_vector(ot_int,0,0,&zero));
    }else if(2==n){
        id primes=make_vector(ot_int,1,1,&zero);
        vector_set_int(primes,0,2);
        return(primes);
    }else if(3==n){
        id primes=make_vector(ot_int,2,2,&zero);
        vector_set_int(primes,0,2);
        vector_set_int(primes,1,3);
        return(primes);
    }else{
        int bits_max;
        int words_max;
        int word_size=8*sizeof(int);
        int* bits;
        int bit;
        int prime_count=2;
        int cur_prime=3;

        n-=(n%1)?3:2;
        bits_max=n/2;
        words_max=(bits_max+word_size-1)/word_size;
        bits=memory_allocate(__FUNCTION__,sizeof(int),words_max);
        for(int i=0;i<words_max;i++){
            bits[i]=(~0);}
        while(cur_prime<n){
            bit=cur_prime+(cur_prime-3)/2;
            while(bit<bits_max){
                bits[bit/word_size]&=(~(1<<bit%word_size));
                bit+=cur_prime;}
            bit=1+((cur_prime-3)/2);
            int pos=bit;
            while((pos<=bits_max) and (0==(bits[pos/word_size]&(1<<pos%word_size)))){
                pos++; }
            bit=pos;
            if(bit<bits_max){
                cur_prime=bit+bit+3;
                prime_count++;
            }else{
                cur_prime=n;
            }}
        // /*DEBUG*/printf("%s(%d) prime_count=%d\n",__FUNCTION__,n,prime_count); fflush(stdout);
        id primes=make_vector(ot_int,(1+prime_count),0,&zero);
        vector_set_fill_pointer(primes,1);
        vector_set_int(primes,0,prime_count);
        int curnum=0;
        vector_set_fill_pointer(primes,1+curnum);
        vector_set_int(primes,curnum++,2);
        vector_set_fill_pointer(primes,1+curnum);
        vector_set_int(primes,curnum++,3);
        bit=1;
        while((bit<=bits_max) and (0==(bits[bit/word_size]&(1<<bit%word_size)))){
            bit++; }
        while((curnum<=prime_count) and (bit<bits_max)){
            cur_prime=bit+bit+3;
            vector_set_fill_pointer(primes,1+curnum);
            vector_set_int(primes,curnum++,cur_prime);
            // /*DEBUG*/printf("%s(%d) prime=%d\n",__FUNCTION__,n,cur_prime); fflush(stdout);
            bit++;
            while((bit<=bits_max) and (0==(bits[bit/word_size]&(1<<bit%word_size)))){
                bit++; }}
        // /*DEBUG*/printf("%s(%d) exit\n",__FUNCTION__,n); fflush(stdout);
        return(primes);}}



id primes=0;

int search_prime(int n,int* order){
    if((nil==primes) or (vector_get_int(primes,vector_length(primes)-1)<n)){
        primes=compute_primes_to(n*2);
    }
    /*
        +-------------------+----------+-------+----------+----------------+
        | Case              |  found   | index |  order   |     Error      |
        +-------------------+----------+-------+----------+----------------+
        | x < a[i]          |   FALSE  |  min  |  less    |      0         |
        | a[i] < x < a[i+1] |   FALSE  |   i   |  greater |      0         |
        | x = a[i]          |   TRUE   |   i   |  equal   |      0         |
        | a[max] < x        |   FALSE  |  max  |  greater |      0         |
        +-------------------+----------+-------+----------+----------------+
    */
    int min=0;
    int max=vector_length(primes)-1;
    int ind=(min+max)/2;
    int cur=vector_get_int(primes,ind);
    int ord=(n==cur)?0:(n<cur)?-1:1;
    while((0!=ord) and (min!=ind)){
        if(ord<0){
            max=ind;
        }else{
            min=ind;
        }
        ind=(min+max)/2;
        cur=vector_get_int(primes,ind);
        ord=(n==cur)?0:(n<cur)?-1:1;}
    if((1<ind)and(ord<0)){
        ord=1;
        ind--;}
    (*order)=ord;
    return(ind);}

bool primep(int n){
    int ord=0;
    search_prime(n,&ord);
    return(ord==0);}

int ceiling_to_nearest_prime(int n){
    int ord=0;
    int ind=search_prime(n,&ord);
    if(ord<0){
        return(vector_get_int(primes,1));
    }else{
        return(vector_get_int(primes,1+ind));
    }}






id prin1_object(id object,FILE* file);
id print_list(id object,FILE* file){
    if(null(object)){
        fprintf(file,"nil");
    }else{
        fprintf(file,"(");
        prin1_object(car(object),file);
        while(consp(object=cdr(object))){
            fprintf(file," ");
            prin1_object(car(object),file);}
        if(not(null(object))){
            fprintf(file," . ");
            prin1_object(object,file);}
        fprintf(file,")");}
    return(object);}


id print_string(id object,FILE* file){
    assert(vectorp(object) and (ot_char==vector_element_type(object)));
    fprintf(file,"\"");
    int count=vector_length(object);
    for(int i=0;i<count;i++){
        char ch=vector_get_char(object,i);
        if(('"'==ch)or('\\'==ch)){
            fprintf(file,"\\%c",ch);
        }else{
            fprintf(file,"%c",ch);}}
    fprintf(file,"\"");
    return(object);}


id print_vector(id object,FILE* file){
    assert(vectorp(object));
    int count=vector_length(object);
    const char* sep="";
    switch(vector_element_type(object)){
      case ot_char:
          print_string(object,file);
          break;
      case ot_int:
          fprintf(file,"#(");
          for(int i=0;i<count;i++){
              fprintf(file,"%s%d",sep,vector_get_int(object,i));
              sep=" ";}
          fprintf(file,")");
          break;
      case ot_t:
          fprintf(file,"#(");
          for(int i=0;i<count;i++){
              prin1_object(vector_get(object,i),file);
              sep=" ";}
          fprintf(file,")");
          break;
      default:
          fprintf(file,"#<vector>");
          break;
    }
    return(object);}


id prin1_object(id object,FILE* file){
    if(null(object)){
        fprintf(file,"nil");
    }else{
        switch(type_of(object)){
          case ot_CXCursor:
              fprintf(file,"#<CXCursor %d>",sxhash(object));
              break;
          case ot_int:
              fprintf(file,"%d",unbox_integer(object));
              break;
          case ot_char:
              fprintf(file,"#\%c",unbox_character(object));
              break;
          case ot_cons:
              print_list(object,file);
              break;
          case ot_vector:
              if(stringp(object)){
                  print_string(object,file);
              }else{
                  print_vector(object,file);
              }
              break;
          case ot_hashtable:
              fprintf(file,"#<hashtable :count %d>",hashtable_count(object));
              break;
          default:
              fprintf(file,"#<OBJECT-OF-UNKNOWN-TYPE>");
              break;
        }}
    return(object);}



//// arguments

id argv_to_list(const char* const* argv){
    id args=nil;
    for(int i=0;argv[i];i++){
        PUSH(string(argv[i]),args);}
    return(nreverse(args));}

const char* const* list_to_argv(id args){
    int cnt=length(args);
    const char** result=memory_allocate(__FUNCTION__,sizeof(char*),(1+cnt));
    for(int i=0;i<cnt;i++,args=rest(args)){
        assert(stringp(car(args)));
        result[i]=unbox_string(car(args));}
    result[cnt]=0;
    return(result);}

int argv_count(const char* const* argv){
    // /*DEBUG*/printf("%s(…)\n",__FUNCTION__); fflush(stdout);
    int cnt=0;
    while(argv[cnt]){
        cnt++;
    }
    return(cnt);}

const char* const* argv_concat(const char* const* argv1,const char* const* argv2){
    // /*DEBUG*/printf("%s(…)\n",__FUNCTION__); fflush(stdout);
    int cnt1=argv_count(argv1);
    int cnt2=argv_count(argv2);
    const char** result=memory_allocate(__FUNCTION__,sizeof(char*),(1+cnt1+cnt2));
    int s=0;
    int d=0;
    for(s=0;s<cnt1;s++){
        result[d++]=argv1[s];}
    for(s=0;s<cnt2;s++){
        result[d++]=argv2[s];}
    result[d]=0;
    return(result);}


//// clang-c



const char* cursorSymbol(int cursorKind){
    switch(cursorKind){
      case CXCursor_UnexposedDecl:                      return ":unexposed-decl";
      case CXCursor_StructDecl:                         return ":struct-decl";
      case CXCursor_UnionDecl:                          return ":union-decl";
      case CXCursor_ClassDecl:                          return ":class-decl";
      case CXCursor_EnumDecl:                           return ":enum-decl";
      case CXCursor_FieldDecl:                          return ":field-decl";
      case CXCursor_EnumConstantDecl:                   return ":enum-constant-decl";
      case CXCursor_FunctionDecl:                       return ":function-decl";
      case CXCursor_VarDecl:                            return ":var-decl";
      case CXCursor_ParmDecl:                           return ":parm-decl";
      case CXCursor_ObjCInterfaceDecl:                  return ":objc-interface-decl";
      case CXCursor_ObjCCategoryDecl:                   return ":objc-category-decl";
      case CXCursor_ObjCProtocolDecl:                   return ":objc-protocol-decl";
      case CXCursor_ObjCPropertyDecl:                   return ":objc-property-decl";
      case CXCursor_ObjCIvarDecl:                       return ":objc-ivar-decl";
      case CXCursor_ObjCInstanceMethodDecl:             return ":objc-instance-method-decl";
      case CXCursor_ObjCClassMethodDecl:                return ":objc-class-method-decl";
      case CXCursor_ObjCImplementationDecl:             return ":objc-implementation-decl";
      case CXCursor_ObjCCategoryImplDecl:               return ":objc-category-impl-decl";
      case CXCursor_TypedefDecl:                        return ":typedef-decl";
      case CXCursor_CXXMethod:                          return ":cxx-method";
      case CXCursor_Namespace:                          return ":namespace";
      case CXCursor_LinkageSpec:                        return ":linkage-spec";
      case CXCursor_Constructor:                        return ":constructor";
      case CXCursor_Destructor:                         return ":destructor";
      case CXCursor_ConversionFunction:                 return ":conversion-function";
      case CXCursor_TemplateTypeParameter:              return ":template-type-parameter";
      case CXCursor_NonTypeTemplateParameter:           return ":non-type-template-parameter";
      case CXCursor_TemplateTemplateParameter:          return ":template-template-parameter";
      case CXCursor_FunctionTemplate:                   return ":function-template";
      case CXCursor_ClassTemplate:                      return ":class-template";
      case CXCursor_ClassTemplatePartialSpecialization: return ":class-template-partial-specialization";
      case CXCursor_NamespaceAlias:                     return ":namespace-alias";
      case CXCursor_UsingDirective:                     return ":using-directive";
      case CXCursor_UsingDeclaration:                   return ":using-declaration";
      case CXCursor_TypeAliasDecl:                      return ":type-alias-decl";
      case CXCursor_ObjCSynthesizeDecl:                 return ":objc-synthesize-decl";
      case CXCursor_ObjCDynamicDecl:                    return ":objc-dynamic-decl";
      case CXCursor_CXXAccessSpecifier:                 return ":cxx-access-specifier";
      case CXCursor_ObjCSuperClassRef:                  return ":objc-super-class-ref";
      case CXCursor_ObjCProtocolRef:                    return ":objc-protocol-ref";
      case CXCursor_ObjCClassRef:                       return ":objc-class-ref";
      case CXCursor_TypeRef:                            return ":type-ref";
      case CXCursor_CXXBaseSpecifier:                   return ":cxx-base-specifier";
      case CXCursor_TemplateRef:                        return ":template-ref";
      case CXCursor_NamespaceRef:                       return ":namespace-ref";
      case CXCursor_MemberRef:                          return ":member-ref";
      case CXCursor_LabelRef:                           return ":label-ref";
      case CXCursor_OverloadedDeclRef:                  return ":overloaded-decl-ref";
      case CXCursor_VariableRef:                        return ":variable-ref";
      case CXCursor_InvalidFile:                        return ":invalid-file";
      case CXCursor_NoDeclFound:                        return ":no-decl-found";
      case CXCursor_NotImplemented:                     return ":not-implemented";
      case CXCursor_InvalidCode:                        return ":invalid-code";
      case CXCursor_UnexposedExpr:                      return ":unexposed-expr";
      case CXCursor_DeclRefExpr:                        return ":decl-ref-expr";
      case CXCursor_MemberRefExpr:                      return ":member-ref-expr";
      case CXCursor_CallExpr:                           return ":call-expr";
      case CXCursor_ObjCMessageExpr:                    return ":objc-message-expr";
      case CXCursor_BlockExpr:                          return ":block-expr";
      case CXCursor_IntegerLiteral:                     return ":integer-literal";
      case CXCursor_FloatingLiteral:                    return ":floating-literal";
      case CXCursor_ImaginaryLiteral:                   return ":imaginary-literal";
      case CXCursor_StringLiteral:                      return ":string-literal";
      case CXCursor_CharacterLiteral:                   return ":character-literal";
      case CXCursor_ParenExpr:                          return ":paren-expr";
      case CXCursor_UnaryOperator:                      return ":unary-operator";
      case CXCursor_ArraySubscriptExpr:                 return ":array-subscript-expr";
      case CXCursor_BinaryOperator:                     return ":binary-operator";
      case CXCursor_CompoundAssignOperator:             return ":compound-assign-operator";
      case CXCursor_ConditionalOperator:                return ":conditional-operator";
      case CXCursor_CStyleCastExpr:                     return ":cstyle-cast-expr";
      case CXCursor_CompoundLiteralExpr:                return ":compound-literal-expr";
      case CXCursor_InitListExpr:                       return ":init-list-expr";
      case CXCursor_AddrLabelExpr:                      return ":addr-label-expr";
      case CXCursor_StmtExpr:                           return ":stmt-expr";
      case CXCursor_GenericSelectionExpr:               return ":generic-selection-expr";
      case CXCursor_GNUNullExpr:                        return ":gnunull-expr";
      case CXCursor_CXXStaticCastExpr:                  return ":cxx-static-cast-expr";
      case CXCursor_CXXDynamicCastExpr:                 return ":cxx-dynamic-cast-expr";
      case CXCursor_CXXReinterpretCastExpr:             return ":cxx-reinterpret-cast-expr";
      case CXCursor_CXXConstCastExpr:                   return ":cxx-const-cast-expr";
      case CXCursor_CXXFunctionalCastExpr:              return ":cxx-functional-cast-expr";
      case CXCursor_CXXTypeidExpr:                      return ":cxx-typeid-expr";
      case CXCursor_CXXBoolLiteralExpr:                 return ":cxx-bool-literal-expr";
      case CXCursor_CXXNullPtrLiteralExpr:              return ":cxx-null-ptr-literal-expr";
      case CXCursor_CXXThisExpr:                        return ":cxx-this-expr";
      case CXCursor_CXXThrowExpr:                       return ":cxx-throw-expr";
      case CXCursor_CXXNewExpr:                         return ":cxx-new-expr";
      case CXCursor_CXXDeleteExpr:                      return ":cxx-delete-expr";
      case CXCursor_UnaryExpr:                          return ":unary-expr";
      case CXCursor_ObjCStringLiteral:                  return ":objc-string-literal";
      case CXCursor_ObjCEncodeExpr:                     return ":objc-encode-expr";
      case CXCursor_ObjCSelectorExpr:                   return ":objc-selector-expr";
      case CXCursor_ObjCProtocolExpr:                   return ":objc-protocol-expr";
      case CXCursor_ObjCBridgedCastExpr:                return ":objc-bridged-cast-expr";
      case CXCursor_PackExpansionExpr:                  return ":pack-expansion-expr";
      case CXCursor_SizeOfPackExpr:                     return ":size-of-pack-expr";
      case CXCursor_LambdaExpr:                         return ":lambda-expr";
      case CXCursor_ObjCBoolLiteralExpr:                return ":objc-bool-literal-expr";
      case CXCursor_UnexposedStmt:                      return ":unexposed-stmt";
      case CXCursor_LabelStmt:                          return ":label-stmt";
      case CXCursor_CompoundStmt:                       return ":compound-stmt";
      case CXCursor_CaseStmt:                           return ":case-stmt";
      case CXCursor_DefaultStmt:                        return ":default-stmt";
      case CXCursor_IfStmt:                             return ":if-stmt";
      case CXCursor_SwitchStmt:                         return ":switch-stmt";
      case CXCursor_WhileStmt:                          return ":while-stmt";
      case CXCursor_DoStmt:                             return ":do-stmt";
      case CXCursor_ForStmt:                            return ":for-stmt";
      case CXCursor_GotoStmt:                           return ":goto-stmt";
      case CXCursor_IndirectGotoStmt:                   return ":indirect-goto-stmt";
      case CXCursor_ContinueStmt:                       return ":continue-stmt";
      case CXCursor_BreakStmt:                          return ":break-stmt";
      case CXCursor_ReturnStmt:                         return ":return-stmt";
      case CXCursor_GCCAsmStmt:                         return ":gccasm-stmt";
      case CXCursor_ObjCAtTryStmt:                      return ":objc-at-try-stmt";
      case CXCursor_ObjCAtCatchStmt:                    return ":objc-at-catch-stmt";
      case CXCursor_ObjCAtFinallyStmt:                  return ":objc-at-finally-stmt";
      case CXCursor_ObjCAtThrowStmt:                    return ":objc-at-throw-stmt";
      case CXCursor_ObjCAtSynchronizedStmt:             return ":objc-at-synchronized-stmt";
      case CXCursor_ObjCAutoreleasePoolStmt:            return ":objc-autorelease-pool-stmt";
      case CXCursor_ObjCForCollectionStmt:              return ":objc-for-collection-stmt";
      case CXCursor_CXXCatchStmt:                       return ":cxx-catch-stmt";
      case CXCursor_CXXTryStmt:                         return ":cxx-try-stmt";
      case CXCursor_CXXForRangeStmt:                    return ":cxx-for-range-stmt";
      case CXCursor_SEHTryStmt:                         return ":seh-try-stmt";
      case CXCursor_SEHExceptStmt:                      return ":seh-except-stmt";
      case CXCursor_SEHFinallyStmt:                     return ":seh-finally-stmt";
      case CXCursor_MSAsmStmt:                          return ":msasm-stmt";
      case CXCursor_NullStmt:                           return ":null-stmt";
      case CXCursor_DeclStmt:                           return ":decl-stmt";
      case CXCursor_TranslationUnit:                    return ":translation-unit";
      case CXCursor_UnexposedAttr:                      return ":unexposed-attr";
      case CXCursor_IBActionAttr:                       return ":ibaction-attr";
      case CXCursor_IBOutletAttr:                       return ":iboutlet-attr";
      case CXCursor_IBOutletCollectionAttr:             return ":iboutlet-collection-attr";
      case CXCursor_CXXFinalAttr:                       return ":cxx-final-attr";
      case CXCursor_CXXOverrideAttr:                    return ":cxx-override-attr";
      case CXCursor_AnnotateAttr:                       return ":annotate-attr";
      case CXCursor_AsmLabelAttr:                       return ":asm-label-attr";
      case CXCursor_PreprocessingDirective:             return ":preprocessing-directive";
      case CXCursor_MacroDefinition:                    return ":macro-definition";
      case CXCursor_MacroExpansion:                     return ":macro-expansion";
      case CXCursor_InclusionDirective:                 return ":inclusion-directive";
      case CXCursor_ModuleImportDecl:                   return ":module-import-decl";
      default:                                          return ":invalid";}}



const char* cursorLinkage(int linkageKind){
    switch(linkageKind){
      case CXLinkage_NoLinkage:      return ":no-linkage";
      case CXLinkage_Internal:       return ":internal";
      case CXLinkage_UniqueExternal: return ":unique-external";
      case CXLinkage_External:       return ":external";
      default:                       return ":invalid";}}


const char* cursorLanguageKind(int languageKind){
    switch(languageKind){
      case CXLanguage_Invalid:   return ":invalid";
      case CXLanguage_C:         return ":c";
      case CXLanguage_ObjC:      return ":objc";
      case CXLanguage_CPlusPlus: return ":cxx";
      default:                   return ":invalid";}}


const char* cursorAvailability(int availabilityKind){
    switch(availabilityKind){
      case CXAvailability_Available:     return ":available";
      case CXAvailability_Deprecated:    return ":deprecated";
      case CXAvailability_NotAvailable:  return ":not-available";
      case CXAvailability_NotAccessible: return ":not-accessible";
      default: return ":invalid";}}



const char* cursorType(int typeKind){
    switch(typeKind){
      case CXType_Invalid:                  return ":Invalid";
      case CXType_Unexposed:                return ":Unexposed";
      case CXType_Void:                     return ":Void";
      case CXType_Bool:                     return ":Bool";
      case CXType_Char_U:                   return ":Char-U";
      case CXType_UChar:                    return ":unsigned-Char";
      case CXType_Char16:                   return ":Char-16";
      case CXType_Char32:                   return ":Char-32";
      case CXType_UShort:                   return ":unsigned-Short";
      case CXType_UInt:                     return ":unsigned-Int";
      case CXType_ULong:                    return ":unsigned-Long";
      case CXType_ULongLong:                return ":unsigned-Long-Long";
      case CXType_UInt128:                  return ":unsigned-Int-128";
      case CXType_Char_S:                   return ":Char-S";
      case CXType_SChar:                    return ":Signed-Char";
      case CXType_WChar:                    return ":Wide-Char";
      case CXType_Short:                    return ":Short";
      case CXType_Int:                      return ":Int";
      case CXType_Long:                     return ":Long";
      case CXType_LongLong:                 return ":Long-Long";
      case CXType_Int128:                   return ":Int-128";
      case CXType_Float:                    return ":Float";
      case CXType_Double:                   return ":Double";
      case CXType_LongDouble:               return ":Long-Double";
      case CXType_NullPtr:                  return ":Null-Pointer";
      case CXType_Overload:                 return ":Overload";
      case CXType_Dependent:                return ":Dependent";
      case CXType_ObjCId:                   return ":ObjC-Id";
      case CXType_ObjCClass:                return ":ObjC-Class";
      case CXType_ObjCSel:                  return ":ObjC-Selector";
      case CXType_Complex:                  return ":Complex";
      case CXType_Pointer:                  return ":Pointer";
      case CXType_BlockPointer:             return ":Block-Pointer";
      case CXType_LValueReference:          return ":left-Value-Reference";
      case CXType_RValueReference:          return ":right-Value-Reference";
      case CXType_Record:                   return ":Record";
      case CXType_Enum:                     return ":Enum";
      case CXType_Typedef:                  return ":Typedef";
      case CXType_ObjCInterface:            return ":ObjC-Interface";
      case CXType_ObjCObjectPointer:        return ":ObjC-Object-Pointer";
      case CXType_FunctionNoProto:          return ":Function-No-Proto";
      case CXType_FunctionProto:            return ":Function-Proto";
      case CXType_ConstantArray:            return ":Constant-Array";
      case CXType_Vector:                   return ":Vector";
      default:                              return ":invalid"; }}


const char* callingConvention(int cc){
    switch(cc){
      case CXCallingConv_Default:           return ":Default";
      case CXCallingConv_C:                 return ":C";
      case CXCallingConv_X86StdCall:        return ":X86StdCall";
      case CXCallingConv_X86FastCall:       return ":X86FastCall";
      case CXCallingConv_X86ThisCall:       return ":X86ThisCall";
      case CXCallingConv_X86Pascal:         return ":X86Pascal";
      case CXCallingConv_AAPCS:             return ":AAPCS";
      case CXCallingConv_AAPCS_VFP:         return ":AAPCS_VFP";
      case CXCallingConv_PnaclCall:         return ":PnaclCall";
          // case CXCallingConv_IntelOclBicc:      return ":IntelOclBicc";
          // case CXCallingConv_Invalid:           return ":Invalid";
      case CXCallingConv_Unexposed:         return ":Unexposed";
      default:                              return ":invalid"; }}

const char* accessSpecifier(int as){
    switch(as){
      case CX_CXXInvalidAccessSpecifier: return ":invalid";
      case CX_CXXPublic:                 return ":public";
      case CX_CXXProtected:              return ":protected";
      case CX_CXXPrivate:                return ":private";
      default:                           return ":invalid";}}


void newline(int margin){
    printf("\n%*s",margin,"");}

/* void print_platform_availability(CXPlatformAvailability availability){ */
/*     printf("(plateform-availability :plateform \"%s\" :introduced \"%s\" :deprecated \"%s\" :obsoleted \"%s\" :unavailable %s :message \"%s\")",availability.Platform */
/* } */


id cxstring(CXString theCXString){
    const char* cstring=clang_getCString(theCXString);
    id result=((nil==cstring)
                    ?nil
                    :string(cstring));
    clang_disposeString(theCXString);
    return(result);}

void print_cxstring(CXString string){
    const char* cstring=clang_getCString(string);
    if(nil==cstring){
        printf("nil");
    }else{
        printf("\"%s\"",cstring);
    }
    clang_disposeString(string);}


void print_location(CXSourceLocation location){
    CXFile file;
    unsigned line;
    unsigned column;
    unsigned offset;
    clang_getSpellingLocation(location,&file,&line,&column,&offset);
    printf("(location :file ");
    if(nil==file){
        printf("nil");
    }else{
        print_cxstring(clang_getFileName(file));
    }
    printf(" :line %u :column %u :offset %u)",line,column,offset);}


void print_range(CXSourceRange range,int margin){
    printf("(range :start ");
    print_location(clang_getRangeStart(range));
    newline(margin);printf("       :end   ");
    print_location(clang_getRangeEnd(range));
    printf(")");}


id cursors=0; // maps CXCursor objects to integer objects.


void print_flag(int margin,const char* name,bool flag){
    newline(imin(60,margin));
    printf(" %s %s",name,flag?"t":"nil");}


void print_cursor(CXCursor cxcursor,int margin);


void print_unexposed_decl(CXCursor cursor,int margin){
}

void print_struct_decl(CXCursor cursor,int margin){
}

void print_union_decl(CXCursor cursor,int margin){
}

void print_class_decl(CXCursor cursor,int margin){
}

void print_enum_decl(CXCursor cursor,int margin){
}

void print_field_decl(CXCursor cursor,int margin){
}

void print_enum_constant_decl(CXCursor cursor,int margin){
}

void print_function_decl(CXCursor cursor,int margin){
}

void print_var_decl(CXCursor cursor,int margin){
}

void print_parm_decl(CXCursor cursor,int margin){
}

void print_objc_interface_decl(CXCursor cursor,int margin){
}

void print_objc_category_decl(CXCursor cursor,int margin){
}

void print_objc_protocol_decl(CXCursor cursor,int margin){
}

void print_objc_property_decl(CXCursor cursor,int margin){
}

void print_objc_ivar_decl(CXCursor cursor,int margin){
}

void print_objc_instance_method_decl(CXCursor cursor,int margin){
}

void print_objc_class_method_decl(CXCursor cursor,int margin){
}

void print_objc_implementation_decl(CXCursor cursor,int margin){
}

void print_objc_category_impl_decl(CXCursor cursor,int margin){
}

void print_typedef_decl(CXCursor cursor,int margin){
}

void print_cxx_method(CXCursor cursor,int margin){
}

void print_namespace(CXCursor cursor,int margin){
}

void print_linkage_spec(CXCursor cursor,int margin){
}

void print_constructor(CXCursor cursor,int margin){
}

void print_destructor(CXCursor cursor,int margin){
}

void print_conversion_function(CXCursor cursor,int margin){
}

void print_template_type_parameter(CXCursor cursor,int margin){
}

void print_non_type_template_parameter(CXCursor cursor,int margin){
}

void print_template_template_parameter(CXCursor cursor,int margin){
}

void print_function_template(CXCursor cursor,int margin){
}

void print_class_template(CXCursor cursor,int margin){
}

void print_class_template_partial_specialization(CXCursor cursor,int margin){
}

void print_namespace_alias(CXCursor cursor,int margin){
}

void print_using_directive(CXCursor cursor,int margin){
}

void print_using_declaration(CXCursor cursor,int margin){
}

void print_type_alias_decl(CXCursor cursor,int margin){
}

void print_objc_synthesize_decl(CXCursor cursor,int margin){
}

void print_objc_dynamic_decl(CXCursor cursor,int margin){
}

void print_cxx_access_specifier(CXCursor cursor,int margin){
}

void print_objc_super_class_ref(CXCursor cursor,int margin){
}

void print_objc_protocol_ref(CXCursor cursor,int margin){
}

void print_objc_class_ref(CXCursor cursor,int margin){
}

void print_type_ref(CXCursor cursor,int margin){
}

void print_cxx_base_specifier(CXCursor cursor,int margin){
}

void print_template_ref(CXCursor cursor,int margin){
}

void print_namespace_ref(CXCursor cursor,int margin){
}

void print_member_ref(CXCursor cursor,int margin){
}

void print_label_ref(CXCursor cursor,int margin){
}

void print_overloaded_decl_ref(CXCursor cursor,int margin){
}

void print_variable_ref(CXCursor cursor,int margin){
}

void print_invalid_file(CXCursor cursor,int margin){
}

void print_no_decl_found(CXCursor cursor,int margin){
}

void print_not_implemented(CXCursor cursor,int margin){
}

void print_invalid_code(CXCursor cursor,int margin){
}

void print_unexposed_expr(CXCursor cursor,int margin){
}

void print_decl_ref_expr(CXCursor cursor,int margin){
}

void print_member_ref_expr(CXCursor cursor,int margin){
}

void print_call_expr(CXCursor cursor,int margin){
}

void print_objc_message_expr(CXCursor cursor,int margin){
}

void print_block_expr(CXCursor cursor,int margin){
}

void print_integer_literal(CXCursor cursor,int margin){
}

void print_floating_literal(CXCursor cursor,int margin){
}

void print_imaginary_literal(CXCursor cursor,int margin){
}

void print_cxstring_literal(CXCursor cursor,int margin){
}

void print_character_literal(CXCursor cursor,int margin){
}

void print_paren_expr(CXCursor cursor,int margin){
}

void print_unary_operator(CXCursor cursor,int margin){
}

void print_array_subscript_expr(CXCursor cursor,int margin){
}

void print_binary_operator(CXCursor cursor,int margin){
}

void print_compound_assign_operator(CXCursor cursor,int margin){
}

void print_conditional_operator(CXCursor cursor,int margin){
}

void print_cstyle_cast_expr(CXCursor cursor,int margin){
}

void print_compound_literal_expr(CXCursor cursor,int margin){
}

void print_init_list_expr(CXCursor cursor,int margin){
}

void print_addr_label_expr(CXCursor cursor,int margin){
}

void print_stmt_expr(CXCursor cursor,int margin){
}

void print_generic_selection_expr(CXCursor cursor,int margin){
}

void print_gnunull_expr(CXCursor cursor,int margin){
}

void print_cxx_static_cast_expr(CXCursor cursor,int margin){
}

void print_cxx_dynamic_cast_expr(CXCursor cursor,int margin){
}

void print_cxx_reinterpret_cast_expr(CXCursor cursor,int margin){
}

void print_cxx_const_cast_expr(CXCursor cursor,int margin){
}

void print_cxx_functional_cast_expr(CXCursor cursor,int margin){
}

void print_cxx_typeid_expr(CXCursor cursor,int margin){
}

void print_cxx_bool_literal_expr(CXCursor cursor,int margin){
}

void print_cxx_null_ptr_literal_expr(CXCursor cursor,int margin){
}

void print_cxx_this_expr(CXCursor cursor,int margin){
}

void print_cxx_throw_expr(CXCursor cursor,int margin){
}

void print_cxx_new_expr(CXCursor cursor,int margin){
}

void print_cxx_delete_expr(CXCursor cursor,int margin){
}

void print_unary_expr(CXCursor cursor,int margin){
}

void print_objc_string_literal(CXCursor cursor,int margin){
}

void print_objc_encode_expr(CXCursor cursor,int margin){
}

void print_objc_selector_expr(CXCursor cursor,int margin){
}

void print_objc_protocol_expr(CXCursor cursor,int margin){
}

void print_objc_bridged_cast_expr(CXCursor cursor,int margin){
}

void print_pack_expansion_expr(CXCursor cursor,int margin){
}

void print_size_of_pack_expr(CXCursor cursor,int margin){
}

void print_lambda_expr(CXCursor cursor,int margin){
}

void print_objc_bool_literal_expr(CXCursor cursor,int margin){
}

void print_unexposed_stmt(CXCursor cursor,int margin){
}

void print_label_stmt(CXCursor cursor,int margin){
}

void print_compound_stmt(CXCursor cursor,int margin){
}

void print_case_stmt(CXCursor cursor,int margin){
}

void print_default_stmt(CXCursor cursor,int margin){
}

void print_if_stmt(CXCursor cursor,int margin){
}

void print_switch_stmt(CXCursor cursor,int margin){
}

void print_while_stmt(CXCursor cursor,int margin){
}

void print_do_stmt(CXCursor cursor,int margin){
}

void print_for_stmt(CXCursor cursor,int margin){
}

void print_goto_stmt(CXCursor cursor,int margin){
}

void print_indirect_goto_stmt(CXCursor cursor,int margin){
}

void print_continue_stmt(CXCursor cursor,int margin){
}

void print_break_stmt(CXCursor cursor,int margin){
}

void print_return_stmt(CXCursor cursor,int margin){
}

void print_gccasm_stmt(CXCursor cursor,int margin){
}

void print_objc_at_try_stmt(CXCursor cursor,int margin){
}

void print_objc_at_catch_stmt(CXCursor cursor,int margin){
}

void print_objc_at_finally_stmt(CXCursor cursor,int margin){
}

void print_objc_at_throw_stmt(CXCursor cursor,int margin){
}

void print_objc_at_synchronized_stmt(CXCursor cursor,int margin){
}

void print_objc_autorelease_pool_stmt(CXCursor cursor,int margin){
}

void print_objc_for_collection_stmt(CXCursor cursor,int margin){
}

void print_cxx_catch_stmt(CXCursor cursor,int margin){
}

void print_cxx_try_stmt(CXCursor cursor,int margin){
}

void print_cxx_for_range_stmt(CXCursor cursor,int margin){
}

void print_seh_try_stmt(CXCursor cursor,int margin){
}

void print_seh_except_stmt(CXCursor cursor,int margin){
}

void print_seh_finally_stmt(CXCursor cursor,int margin){
}

void print_msasm_stmt(CXCursor cursor,int margin){
}

void print_null_stmt(CXCursor cursor,int margin){
}

void print_decl_stmt(CXCursor cursor,int margin){
}

void print_translation_unit(CXCursor cursor,int margin){
}

void print_unexposed_attr(CXCursor cursor,int margin){
}

void print_ibaction_attr(CXCursor cursor,int margin){
}

void print_iboutlet_attr(CXCursor cursor,int margin){
}

void print_iboutlet_collection_attr(CXCursor cursor,int margin){
}

void print_cxx_final_attr(CXCursor cursor,int margin){
}

void print_cxx_override_attr(CXCursor cursor,int margin){
}

void print_annotate_attr(CXCursor cursor,int margin){
}

void print_asm_label_attr(CXCursor cursor,int margin){
}

void print_preprocessing_directive(CXCursor cursor,int margin){
}

void print_macro_definition(CXCursor cursor,int margin){
}

void print_macro_expansion(CXCursor cursor,int margin){
}

void print_inclusion_directive(CXCursor cursor,int margin){
}

void print_module_import_decl(CXCursor cursor,int margin){
}

void print_invalid(CXCursor cursor,int margin){
}




typedef void(*printer)(CXCursor,int);

printer cursor_printer(int cursorKind){
    switch(cursorKind){
      case CXCursor_UnexposedDecl:                      return print_unexposed_decl;
      case CXCursor_StructDecl:                         return print_struct_decl;
      case CXCursor_UnionDecl:                          return print_union_decl;
      case CXCursor_ClassDecl:                          return print_class_decl;
      case CXCursor_EnumDecl:                           return print_enum_decl;
      case CXCursor_FieldDecl:                          return print_field_decl;
      case CXCursor_EnumConstantDecl:                   return print_enum_constant_decl;
      case CXCursor_FunctionDecl:                       return print_function_decl;
      case CXCursor_VarDecl:                            return print_var_decl;
      case CXCursor_ParmDecl:                           return print_parm_decl;
      case CXCursor_ObjCInterfaceDecl:                  return print_objc_interface_decl;
      case CXCursor_ObjCCategoryDecl:                   return print_objc_category_decl;
      case CXCursor_ObjCProtocolDecl:                   return print_objc_protocol_decl;
      case CXCursor_ObjCPropertyDecl:                   return print_objc_property_decl;
      case CXCursor_ObjCIvarDecl:                       return print_objc_ivar_decl;
      case CXCursor_ObjCInstanceMethodDecl:             return print_objc_instance_method_decl;
      case CXCursor_ObjCClassMethodDecl:                return print_objc_class_method_decl;
      case CXCursor_ObjCImplementationDecl:             return print_objc_implementation_decl;
      case CXCursor_ObjCCategoryImplDecl:               return print_objc_category_impl_decl;
      case CXCursor_TypedefDecl:                        return print_typedef_decl;
      case CXCursor_CXXMethod:                          return print_cxx_method;
      case CXCursor_Namespace:                          return print_namespace;
      case CXCursor_LinkageSpec:                        return print_linkage_spec;
      case CXCursor_Constructor:                        return print_constructor;
      case CXCursor_Destructor:                         return print_destructor;
      case CXCursor_ConversionFunction:                 return print_conversion_function;
      case CXCursor_TemplateTypeParameter:              return print_template_type_parameter;
      case CXCursor_NonTypeTemplateParameter:           return print_non_type_template_parameter;
      case CXCursor_TemplateTemplateParameter:          return print_template_template_parameter;
      case CXCursor_FunctionTemplate:                   return print_function_template;
      case CXCursor_ClassTemplate:                      return print_class_template;
      case CXCursor_ClassTemplatePartialSpecialization: return print_class_template_partial_specialization;
      case CXCursor_NamespaceAlias:                     return print_namespace_alias;
      case CXCursor_UsingDirective:                     return print_using_directive;
      case CXCursor_UsingDeclaration:                   return print_using_declaration;
      case CXCursor_TypeAliasDecl:                      return print_type_alias_decl;
      case CXCursor_ObjCSynthesizeDecl:                 return print_objc_synthesize_decl;
      case CXCursor_ObjCDynamicDecl:                    return print_objc_dynamic_decl;
      case CXCursor_CXXAccessSpecifier:                 return print_cxx_access_specifier;
      case CXCursor_ObjCSuperClassRef:                  return print_objc_super_class_ref;
      case CXCursor_ObjCProtocolRef:                    return print_objc_protocol_ref;
      case CXCursor_ObjCClassRef:                       return print_objc_class_ref;
      case CXCursor_TypeRef:                            return print_type_ref;
      case CXCursor_CXXBaseSpecifier:                   return print_cxx_base_specifier;
      case CXCursor_TemplateRef:                        return print_template_ref;
      case CXCursor_NamespaceRef:                       return print_namespace_ref;
      case CXCursor_MemberRef:                          return print_member_ref;
      case CXCursor_LabelRef:                           return print_label_ref;
      case CXCursor_OverloadedDeclRef:                  return print_overloaded_decl_ref;
      case CXCursor_VariableRef:                        return print_variable_ref;
      case CXCursor_InvalidFile:                        return print_invalid_file;
      case CXCursor_NoDeclFound:                        return print_no_decl_found;
      case CXCursor_NotImplemented:                     return print_not_implemented;
      case CXCursor_InvalidCode:                        return print_invalid_code;
      case CXCursor_UnexposedExpr:                      return print_unexposed_expr;
      case CXCursor_DeclRefExpr:                        return print_decl_ref_expr;
      case CXCursor_MemberRefExpr:                      return print_member_ref_expr;
      case CXCursor_CallExpr:                           return print_call_expr;
      case CXCursor_ObjCMessageExpr:                    return print_objc_message_expr;
      case CXCursor_BlockExpr:                          return print_block_expr;
      case CXCursor_IntegerLiteral:                     return print_integer_literal;
      case CXCursor_FloatingLiteral:                    return print_floating_literal;
      case CXCursor_ImaginaryLiteral:                   return print_imaginary_literal;
      case CXCursor_StringLiteral:                      return print_cxstring_literal;
      case CXCursor_CharacterLiteral:                   return print_character_literal;
      case CXCursor_ParenExpr:                          return print_paren_expr;
      case CXCursor_UnaryOperator:                      return print_unary_operator;
      case CXCursor_ArraySubscriptExpr:                 return print_array_subscript_expr;
      case CXCursor_BinaryOperator:                     return print_binary_operator;
      case CXCursor_CompoundAssignOperator:             return print_compound_assign_operator;
      case CXCursor_ConditionalOperator:                return print_conditional_operator;
      case CXCursor_CStyleCastExpr:                     return print_cstyle_cast_expr;
      case CXCursor_CompoundLiteralExpr:                return print_compound_literal_expr;
      case CXCursor_InitListExpr:                       return print_init_list_expr;
      case CXCursor_AddrLabelExpr:                      return print_addr_label_expr;
      case CXCursor_StmtExpr:                           return print_stmt_expr;
      case CXCursor_GenericSelectionExpr:               return print_generic_selection_expr;
      case CXCursor_GNUNullExpr:                        return print_gnunull_expr;
      case CXCursor_CXXStaticCastExpr:                  return print_cxx_static_cast_expr;
      case CXCursor_CXXDynamicCastExpr:                 return print_cxx_dynamic_cast_expr;
      case CXCursor_CXXReinterpretCastExpr:             return print_cxx_reinterpret_cast_expr;
      case CXCursor_CXXConstCastExpr:                   return print_cxx_const_cast_expr;
      case CXCursor_CXXFunctionalCastExpr:              return print_cxx_functional_cast_expr;
      case CXCursor_CXXTypeidExpr:                      return print_cxx_typeid_expr;
      case CXCursor_CXXBoolLiteralExpr:                 return print_cxx_bool_literal_expr;
      case CXCursor_CXXNullPtrLiteralExpr:              return print_cxx_null_ptr_literal_expr;
      case CXCursor_CXXThisExpr:                        return print_cxx_this_expr;
      case CXCursor_CXXThrowExpr:                       return print_cxx_throw_expr;
      case CXCursor_CXXNewExpr:                         return print_cxx_new_expr;
      case CXCursor_CXXDeleteExpr:                      return print_cxx_delete_expr;
      case CXCursor_UnaryExpr:                          return print_unary_expr;
      case CXCursor_ObjCStringLiteral:                  return print_objc_string_literal;
      case CXCursor_ObjCEncodeExpr:                     return print_objc_encode_expr;
      case CXCursor_ObjCSelectorExpr:                   return print_objc_selector_expr;
      case CXCursor_ObjCProtocolExpr:                   return print_objc_protocol_expr;
      case CXCursor_ObjCBridgedCastExpr:                return print_objc_bridged_cast_expr;
      case CXCursor_PackExpansionExpr:                  return print_pack_expansion_expr;
      case CXCursor_SizeOfPackExpr:                     return print_size_of_pack_expr;
      case CXCursor_LambdaExpr:                         return print_lambda_expr;
      case CXCursor_ObjCBoolLiteralExpr:                return print_objc_bool_literal_expr;
      case CXCursor_UnexposedStmt:                      return print_unexposed_stmt;
      case CXCursor_LabelStmt:                          return print_label_stmt;
      case CXCursor_CompoundStmt:                       return print_compound_stmt;
      case CXCursor_CaseStmt:                           return print_case_stmt;
      case CXCursor_DefaultStmt:                        return print_default_stmt;
      case CXCursor_IfStmt:                             return print_if_stmt;
      case CXCursor_SwitchStmt:                         return print_switch_stmt;
      case CXCursor_WhileStmt:                          return print_while_stmt;
      case CXCursor_DoStmt:                             return print_do_stmt;
      case CXCursor_ForStmt:                            return print_for_stmt;
      case CXCursor_GotoStmt:                           return print_goto_stmt;
      case CXCursor_IndirectGotoStmt:                   return print_indirect_goto_stmt;
      case CXCursor_ContinueStmt:                       return print_continue_stmt;
      case CXCursor_BreakStmt:                          return print_break_stmt;
      case CXCursor_ReturnStmt:                         return print_return_stmt;
      case CXCursor_GCCAsmStmt:                         return print_gccasm_stmt;
      case CXCursor_ObjCAtTryStmt:                      return print_objc_at_try_stmt;
      case CXCursor_ObjCAtCatchStmt:                    return print_objc_at_catch_stmt;
      case CXCursor_ObjCAtFinallyStmt:                  return print_objc_at_finally_stmt;
      case CXCursor_ObjCAtThrowStmt:                    return print_objc_at_throw_stmt;
      case CXCursor_ObjCAtSynchronizedStmt:             return print_objc_at_synchronized_stmt;
      case CXCursor_ObjCAutoreleasePoolStmt:            return print_objc_autorelease_pool_stmt;
      case CXCursor_ObjCForCollectionStmt:              return print_objc_for_collection_stmt;
      case CXCursor_CXXCatchStmt:                       return print_cxx_catch_stmt;
      case CXCursor_CXXTryStmt:                         return print_cxx_try_stmt;
      case CXCursor_CXXForRangeStmt:                    return print_cxx_for_range_stmt;
      case CXCursor_SEHTryStmt:                         return print_seh_try_stmt;
      case CXCursor_SEHExceptStmt:                      return print_seh_except_stmt;
      case CXCursor_SEHFinallyStmt:                     return print_seh_finally_stmt;
      case CXCursor_MSAsmStmt:                          return print_msasm_stmt;
      case CXCursor_NullStmt:                           return print_null_stmt;
      case CXCursor_DeclStmt:                           return print_decl_stmt;
      case CXCursor_TranslationUnit:                    return print_translation_unit;
      case CXCursor_UnexposedAttr:                      return print_unexposed_attr;
      case CXCursor_IBActionAttr:                       return print_ibaction_attr;
      case CXCursor_IBOutletAttr:                       return print_iboutlet_attr;
      case CXCursor_IBOutletCollectionAttr:             return print_iboutlet_collection_attr;
      case CXCursor_CXXFinalAttr:                       return print_cxx_final_attr;
      case CXCursor_CXXOverrideAttr:                    return print_cxx_override_attr;
      case CXCursor_AnnotateAttr:                       return print_annotate_attr;
      case CXCursor_AsmLabelAttr:                       return print_asm_label_attr;
      case CXCursor_PreprocessingDirective:             return print_preprocessing_directive;
      case CXCursor_MacroDefinition:                    return print_macro_definition;
      case CXCursor_MacroExpansion:                     return print_macro_expansion;
      case CXCursor_InclusionDirective:                 return print_inclusion_directive;
      case CXCursor_ModuleImportDecl:                   return print_module_import_decl;
      default:                                          return print_invalid;}}








void reset_visited_flag(id key,id value,void* data){
    setcar(second(value),integer(0));}

void reset_visited_hashtable(id visited){
    hashtable_map(visited,reset_visited_flag,0);}



typedef void (*visit_once_cursors_function)(id ident_number,id label,id cxcursor,id parent,void* function_closure);
typedef struct {
    id                          visited; // maps cursors to (#n# visited-0/1 …)
    visit_once_cursors_function prefix;
    visit_once_cursors_function function;
    visit_once_cursors_function suffix;
    void*                       function_closure;
} visit_once_cursors_closure;

enum CXChildVisitResult visit_once_cursors(CXCursor cxcursor,CXCursor parent,CXClientData client_data){
    /*
    Calls the closure `function' for each arc labelled by `label' going
    from `parent' to some cursor `cxcursor'.
    */
    visit_once_cursors_closure* closure=client_data;
    id                          visited=closure->visited;
    visit_once_cursors_function function=closure->function;
    void*                       function_closure=closure->function_closure;

    id p=cursor(parent);
    id c=cursor(cxcursor);
    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(cxcursor));
    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(unbox_cursor(c)));
    id n=hashtable_get(visited,c);
    id ident_number=first(n);
    id child=string(":child");
    closure->prefix(ident_number,child,c,p,function_closure);
    if(null(n)){
        id entry=list(2,integer(hashtable_count(visited)),integer(0));
        hashtable_set(visited,c,entry);

        CXTranslationUnit tu=clang_Cursor_getTranslationUnit(cxcursor);
        CXCursor tucursor=clang_getTranslationUnitCursor(tu);
        if(not(clang_Cursor_isNull(tucursor))){
            id cc=cursor(tucursor);
            function(first(hashtable_get(visited,cc)),string(":translation-unit"),cc,c,function_closure);}

        CXCursor separent=clang_getCursorSemanticParent(cxcursor);
        if(not(clang_Cursor_isNull(separent))){
            id cc=cursor(separent);
            function(first(hashtable_get(visited,cc)),string(":semantic-parent"),cc,c,function_closure);}

        CXCursor leparent=clang_getCursorLexicalParent(cxcursor);
        if(not(clang_Cursor_isNull(leparent))){
            id cc=cursor(leparent);
            function(first(hashtable_get(visited,cc)),string(":lexical-parent"),cc,c,function_closure);}

        // clang_getOverriddenCursors(cxcursor,&overridden,&num_overridden);
        // clang_disposeOverriddenCursors(overridden);


        /* CXType type=clang_getCursorType(cxcursor); */
        /* if(CXType_Invalid!=type.kind){ */
        /*     newline(margin); printf(" :type %s",cursorType(type.kind));} */
        /*  */
        /* CXType underType=clang_getTypedefDeclUnderlyingType(cxcursor); */
        /* if(CXType_Invalid!=type.kind){ */
        /*     newline(margin); printf(" :underlying-type %s",cursorType(underType.kind));} */
        /*  */
        /* CXType enumType=clang_getEnumDeclIntegerType(cxcursor); */
        /* if(CXType_Invalid!=type.kind){ */
        /*     newline(margin); printf(" :enum-type %s",cursorType(enumType.kind));} */

        int numArguments=clang_Cursor_getNumArguments(cxcursor);
        if(0<=numArguments){
            for(int i=0;i<numArguments;i++){
                id cc=cursor(clang_Cursor_getArgument(cxcursor,i));
                function(first(hashtable_get(visited,cc)),string(":argument"),cc,c,function_closure);}}

        unsigned numOver=clang_getNumOverloadedDecls(cxcursor);
        if(0<numOver){
            for(int i=0;i<numOver;i++){
                id cc=cursor(clang_getOverloadedDecl(cxcursor,i));
                function(first(hashtable_get(visited,cc)),string(":overloaded-declaration"),cc,c,function_closure);}}

        CXCursor definition=clang_getCursorDefinition(cxcursor);
        if(not(clang_Cursor_isNull(definition))){
            id cc=cursor(definition);
            function(first(hashtable_get(visited,cc)),string(":definition"),cc,c,function_closure);}

        CXCursor canonical=clang_getCanonicalCursor(cxcursor);
        if(not(clang_Cursor_isNull(canonical))){
            id cc=cursor(canonical);
            function(first(hashtable_get(visited,cc)),string(":canonical"),cc,c,function_closure);}

        clang_visitChildren(cxcursor,visit_once_cursors,client_data);}
    closure->suffix(ident_number,child,c,p,function_closure);
    return CXChildVisit_Continue;}






/* typedef void (*visit_once_cursors_function)(id ident_number,id label,id cxcursor,id parent,void* function_closure); */
/* typedef struct { */
/*     id                          visited; // maps cursors to (#n# visited-0/1 …) */
/*     visit_once_cursors_function prefix; */
/*     visit_once_cursors_function function; */
/*     visit_once_cursors_function suffix; */
/*     void*                       function_closure; */
/* } visit_once_cursors_closure; */

typedef struct {
    visit_once_cursors_closure vocc;
    int margin;
    bool first;
} print_cursor_visitor_closure;

void print_cursor_visitor_prefix(id ident_number,id label,id cxcursor,id parent,void* function_closure){
}

void print_cursor_visitor_infix(id ident_number,id label,id cxcursor,id parent,void* function_closure){
}

void print_cursor_visitor_suffix(id ident_number,id label,id cxcursor,id parent,void* function_closure){
}

/* { */
/* print_cursor_visitor_closure closure; */
/* closure.vocc.visited=cursors; */
/* closure.vocc.prefix=print_cursor_visitor_prefix; */
/* closure.vocc.function=print_cursor_visitor_infix; */
/* closure.vocc.suffix=print_cursor_visitor_suffix; */
/* closure.vocc.function_closure=&closure; */
/* closure.margin=0; */
/* closure.first=false; */
/* } */


/* enum CXChildVisitResult print_cursor_visitor(CXCursor cursor,CXCursor parent,CXClientData client_data){ */
/*     margin_closure* mc=client_data; */
/*     if(mc->first){ */
/*         mc->first=false; */
/*     }else{ */
/*         newline(mc->margin); */
/*     } */
/*     print_cursor(cursor,mc->margin); */
/*     return(CXChildVisit_Continue);}  */



void print_slots(CXCursor cxcursor,int kind,int margin){
    print_flag(margin,":is-declaration",clang_isDeclaration(kind));
    print_flag(margin,":is-reference",clang_isReference(kind));
    print_flag(margin,":is-expression",clang_isExpression(kind));
    print_flag(margin,":is-statement",clang_isStatement(kind));
    print_flag(margin,":is-attribute",clang_isAttribute(kind));
    print_flag(margin,":is-invaild",clang_isInvalid(kind));
    print_flag(margin,":is-translation-unit",clang_isTranslationUnit(kind));
    print_flag(margin,":is-preprocessing",clang_isPreprocessing(kind));
    print_flag(margin,":is-unexposed",clang_isUnexposed(kind));
    newline(margin);printf(" :linkage %s",cursorLinkage(clang_getCursorLinkage(cxcursor)));

    /* clang_getCursorPlatformAvailability(CXCursor cursor, */
    /*                                     int *always_deprecated, */
    /*                                     CXString *deprecated_message, */
    /*                                     int *always_unavailable, */
    /*                                     CXString *unavailable_message, */
    /*                                     CXPlatformAvailability *availability, */
    /*                                     int availability_size) */
    /* newline(margin);printf(" :availability %s",cursorAvailability(clang_getCursorAvailability(cxcursor))); */

    /* clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability); */

    newline(margin);printf(" :language %s",cursorLanguageKind(clang_getCursorLanguage(cxcursor)));

    if(not(null(cursors))){

        CXTranslationUnit tu=clang_Cursor_getTranslationUnit(cxcursor);
        CXCursor tucursor=clang_getTranslationUnitCursor(tu);
        newline(margin);
        printf(" :translation-unit ");
        print_cursor(tucursor,margin+19);

        CXCursor separent=clang_getCursorSemanticParent(cxcursor);
        newline(margin);
        printf(" :semantic-parent ");
        print_cursor(separent,margin+18);

        CXCursor leparent=clang_getCursorLexicalParent(cxcursor);
        newline(margin);
        printf(" :lexical-parent ");
        print_cursor(leparent,margin+17);
    }
    // clang_getOverriddenCursors(cxcursor,&overridden,&num_overridden);
    // clang_disposeOverriddenCursors(overridden);
    CXFile includedFile=clang_getIncludedFile(cxcursor);
    if(includedFile){
        newline(margin);
        printf(" :included-file ");
        print_cxstring(clang_getFileName(includedFile));
    }


    newline(margin); printf(" :location ");
    print_location(clang_getCursorLocation(cxcursor));
    newline(margin); printf(" :range ");
    print_range(clang_getCursorExtent(cxcursor),margin+8);

    // clang_getCanonicalType(CXType T)

    CXType type=clang_getCursorType(cxcursor);
    if(CXType_Invalid!=type.kind){
        newline(margin); printf(" :type %s",cursorType(type.kind));}

    CXType underType=clang_getTypedefDeclUnderlyingType(cxcursor);
    if(CXType_Invalid!=type.kind){
        newline(margin); printf(" :underlying-type %s",cursorType(underType.kind));}

    CXType enumType=clang_getEnumDeclIntegerType(cxcursor);
    if(CXType_Invalid!=type.kind){
        newline(margin); printf(" :enum-type %s",cursorType(enumType.kind));}


    long long enumConstant=clang_getEnumConstantDeclValue(cxcursor);
    if(CXType_Invalid!=type.kind){
        newline(margin); printf(" :enum-constant %lld",enumConstant);}

    unsigned long long uEnumConstant=clang_getEnumConstantDeclUnsignedValue(cxcursor);
    if(CXType_Invalid!=type.kind){
        newline(margin); printf(" :unsigned-enum-constant %llu",uEnumConstant);}

    /* int fieldBitWidth=clang_getFieldDeclBitWidth(cxcursor); */
    /* if(0<=fieldBitWidth){ */
    /*    newline(margin); printf(" :field-bit-width %d",fieldBitWidth);} */

    int numArguments=clang_Cursor_getNumArguments(cxcursor);
    if(0<=numArguments){
       newline(margin); printf(" :number-of-arguments %d",numArguments);
       newline(margin); printf(" :arguments (");
       for(int i=0;i<numArguments;i++){
           CXCursor arg=clang_Cursor_getArgument(cxcursor,i);
           if(0<i){newline(margin+13);}
           print_cursor(arg,margin+13);}
       printf(")");}

    int as=clang_getCXXAccessSpecifier(cxcursor);
    if(CX_CXXInvalidAccessSpecifier!=as){
        newline(margin); printf(" :access-specifier %s",accessSpecifier(as));}

    unsigned numOver=clang_getNumOverloadedDecls(cxcursor);
    for(unsigned i=0;i<numOver;i++){
       newline(margin); printf(" :number-of-overloaded-declarations %d",numOver);
       newline(margin); printf(" :overloaded-declarations (");
       for(int i=0;i<numOver;i++){
           CXCursor arg=clang_getOverloadedDecl(cxcursor,i);
           if(0<i){newline(margin+27);}
           print_cursor(arg,margin+27);}
       printf(")");}

    // CXType clang_getIBOutletCollectionType(CXCursor);

    // CXString clang_getCursorUSR(CXCursor);
    // CXString clang_constructUSR_ObjCClass(const char *class_name);
    // CXString clang_constructUSR_ObjCCategory(const char *class_name,const char *category_name);
    // CXString clang_constructUSR_ObjCProtocol(const char *protocol_name);
    // CXString clang_constructUSR_ObjCIvar(const char *name,CXString classUSR);
    // CXString clang_constructUSR_ObjCMethod(const char *name,unsigned isInstanceMethod,CXString classUSR);


    // clang_getCursorReferenced() to determine whether a
    // particular cursor refers to another entity.

    CXCursor definition=clang_getCursorDefinition(cxcursor);
    if(not(clang_Cursor_isNull(definition))){
        newline(margin);printf(" :definition ");
        print_cursor(definition,margin+13);}

    print_flag(margin,":is-definition",clang_isCursorDefinition(cxcursor));

    CXCursor canonical=clang_getCanonicalCursor(cxcursor);
    if(not(clang_Cursor_isNull(canonical))){
        newline(margin);printf(" :canonical ");
        print_cursor(canonical,margin+13);}

    newline(margin);
    printf(" :children (");
    /* margin_closure mc; */
    /* mc.first=true; */
    /* mc.margin=margin+12; */
    /* clang_visitChildren(cxcursor,print_cursor_visitor,&mc); */
    printf(")");

    cursor_printer(kind)(cxcursor,margin+1);}


void print_cursor(CXCursor cxcursor,int margin){
    if(clang_Cursor_isNull(cxcursor)){
        printf("nil");
    }else{
        id pair=hashtable_get(cursors,cursor(cxcursor));
        if(null(pair)){
            int kind=clang_getCursorKind(cxcursor);
            printf("(%s",cursorSymbol(kind));
            print_slots(cxcursor,kind,margin+1);
            printf(")");
        }else if(integerp(second(pair)) and (1==unbox_integer(second(pair)))){
            printf("#%d#",unbox_integer(car(pair)));
        }else{
            int kind=clang_getCursorKind(cxcursor);
            printf("#%d=(%s",unbox_integer(first(pair)),cursorSymbol(kind));
            setcar(second(pair),integer(1));
            print_slots(cxcursor,kind,margin+4);//TODO: width of #nn=
            printf(")");}}}


void print_registered_cursor(id cursor,id pair,void* data){
    printf("\n#%d=",unbox_integer(car(pair)));
    print_cursor(unbox_cursor(cursor),0);}




typedef struct {
    visit_once_cursors_closure vocc;
    id linkedCursors;
    id current;
} collect_cursors_visitor_closure;

void collect_cursor_visitor_prefix(id ident_number,id label,id cxcursor,id parent,void* function_closure){
    collect_cursors_visitor_closure* closure=function_closure;
    closure->current=nil;}

void collect_cursor_visitor_infix(id ident_number,id label,id cxcursor,id parent,void* function_closure){
    collect_cursors_visitor_closure* closure=function_closure;
    PUSH2(label,cxcursor,closure->current);}

void collect_cursor_visitor_suffix(id ident_number,id label,id cxcursor,id parent,void* function_closure){
    collect_cursors_visitor_closure* closure=function_closure;
    PUSH(cxcursor,closure->current);
    PUSH(closure->current,closure->linkedCursors);}


enum CXChildVisitResult visit_cursor_collect_children(CXCursor cxcursor,CXCursor parent,CXClientData client_data){
    // Collects the linked and children CXCursors.
    visit_once_cursors_closure* closure=client_data;
    id visited=closure->visited;
    id linkedCursors=nil;

    id c=box(ot_CXCursor,cxcursor);
    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(cxcursor));
    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(unbox_cursor(c)));
    id n=hashtable_get(visited,c);
    if(null(n)){
        id entry=list(3,integer(hashtable_count(visited)),integer(0),nil);
        hashtable_set(visited,c,entry);

        CXTranslationUnit tu=clang_Cursor_getTranslationUnit(cxcursor);
        CXCursor tucursor=clang_getTranslationUnitCursor(tu);
        if(not(clang_Cursor_isNull(tucursor))){
            PUSH2(string(":translation-unit"),cursor(tucursor),linkedCursors);}

        CXCursor separent=clang_getCursorSemanticParent(cxcursor);
        if(not(clang_Cursor_isNull(separent))){
            PUSH2(string(":semantic-parent"),cursor(separent),linkedCursors);}

        CXCursor leparent=clang_getCursorLexicalParent(cxcursor);
        if(not(clang_Cursor_isNull(leparent))){
            PUSH2(string(":lexical-parent"),cursor(leparent),linkedCursors);}

        // clang_getOverriddenCursors(cxcursor,&overridden,&num_overridden);
        // clang_disposeOverriddenCursors(overridden);


        /* CXType type=clang_getCursorType(cxcursor); */
        /* if(CXType_Invalid!=type.kind){ */
        /*     newline(margin); printf(" :type %s",cursorType(type.kind));} */
        /*  */
        /* CXType underType=clang_getTypedefDeclUnderlyingType(cxcursor); */
        /* if(CXType_Invalid!=type.kind){ */
        /*     newline(margin); printf(" :underlying-type %s",cursorType(underType.kind));} */
        /*  */
        /* CXType enumType=clang_getEnumDeclIntegerType(cxcursor); */
        /* if(CXType_Invalid!=type.kind){ */
        /*     newline(margin); printf(" :enum-type %s",cursorType(enumType.kind));} */



        int numArguments=clang_Cursor_getNumArguments(cxcursor);
        if(0<=numArguments){
            id arguments=nil;
            for(int i=0;i<numArguments;i++){
                PUSH(cursor(clang_Cursor_getArgument(cxcursor,i)),arguments);}
            PUSH2(string(":arguments"),arguments,linkedCursors);}

        unsigned numOver=clang_getNumOverloadedDecls(cxcursor);
        if(0<numOver){
            id odecls=nil;
            for(int i=0;i<numOver;i++){
                PUSH(cursor(clang_getOverloadedDecl(cxcursor,i)),odecls);}
            PUSH2(string(":overloaded-declarations"),odecls,linkedCursors);}

        CXCursor definition=clang_getCursorDefinition(cxcursor);
        if(not(clang_Cursor_isNull(definition))){
            PUSH2(string(":definition"),cursor(definition),linkedCursors);}

        CXCursor canonical=clang_getCanonicalCursor(cxcursor);
        if(not(clang_Cursor_isNull(canonical))){
            PUSH2(string(":canonical"),cursor(canonical),linkedCursors);}


        /* visit_once_cursors_closure children_closure; */
        /* children_closure.visited=visited; */
        /* children_closure.linkedCursors=nil; */
        /* clang_visitChildren(cxcursor,visit_cursor_collect_children,&children_closure); */
        /* PUSH2(string(":children"),children_closure.linkedCursors,linkedCursors); */
        /*  */
        /* closure->linkedCursors=linkedCursors; */
        setcar(nthcdr(2,entry),linkedCursors);}
    return CXChildVisit_Continue;}



// PUSH2(string(":usr"),cxstring(clang_getCursorUSR(cxcursor)),cxdata);

// CXType clang_getIBOutletCollectionType(CXCursor);

//
// CXString clang_constructUSR_ObjCClass(const char *class_name);
// CXString clang_constructUSR_ObjCCategory(const char *class_name,const char *category_name);
// CXString clang_constructUSR_ObjCProtocol(const char *protocol_name);
// CXString clang_constructUSR_ObjCIvar(const char *name,CXString classUSR);
// CXString clang_constructUSR_ObjCMethod(const char *name,unsigned isInstanceMethod,CXString classUSR);


// clang_getCursorReferenced() to determine whether a
// particular cursor refers to another entity.



/* void register_cursors(hashtable* cursors,CXCursor rootCursor){ */
/*     visit_cursor_closure closure; */
/*     closure.visited=cursors; */
/*     closure.linkedCursors=nil; */
/*     visit_cursor_collect_children(rootCursor,clang_getNullCursor(),&closure);} */
/*  */
/* typedef struct{ */
/*     bool present; */
/*     int counter; */
/*     CXCursor cxcursor; */
/* } present_closure; */
/*  */
/* void record_cursor_present(id key,id value,void* data){ */
/*     present_closure* closure=data; */
/*     assert(ot_CXCursor==type_of(key)); */
/*     INCF(closure->counter); */
/*     bool areEqual=clang_equalCursors(unbox_cursor(key),closure->cxcursor); */
/*     /\* printf("\n%s\n",areEqual?"EQUAL":"-"); *\/ */
/*     /\* printf("key %5d %5d %20p %20p %20p\n",key->value.cursor.kind,key->value.cursor.xdata,key->value.cursor.data[0],key->value.cursor.data[1],key->value.cursor.data[2]); *\/ */
/*     /\* printf("cur %5d %5d %20p %20p %20p\n",closure->cxcursor.kind,closure->cxcursor.xdata,closure->cxcursor.data[0],closure->cxcursor.data[1],closure->cxcursor.data[2]); *\/ */
/*     if(clang_equalCursors(unbox_cursor(key),closure->cxcursor)){ */
/*         assert(clang_hashCursor(unbox_cursor(key))==clang_hashCursor(closure->cxcursor)); */
/*         closure->present=true;}} */
/*  */
/* void check_cursor_present(hashtable* cursors,CXCursor cxcursor){ */
/*     present_closure closure; */
/*     closure.present=false; */
/*     closure.counter=0; */
/*     closure.cxcursor=cxcursor; */
/*     assert(0<hashtable_count(cursors)); */
/*     hashtable_map(cursors,record_cursor_present,&closure); */
/*     /\* printf("counter=%d\n",closure.counter); *\/ */
/*     assert(0<closure.counter); */
/*     assert(closure.present);} */


void test_all(void);


int main(int argc,const char* const* argv){
    const char* pname=argv[0];
    id args=argv_to_list(argv);
    POP(args);
    if(equal(first(args),string("--test"))){
        POP(args);
        test_all();
        if(null(args)){
            exit(0);}}
    if(null(args)){
        ERROR("Command %s is missing a source file argument.",pname);
        return(1);}
    const char* sourceFile=unbox_string(POP(args));
    id includes=list(1,string("-I/opt/llvm/lib/clang/3.3/include"));
    const char* const* subArgv=list_to_argv(append(2,includes,args));
    int subArgc=argv_count(subArgv);
    CXIndex idx=clang_createIndex(0,1);
    cursors=make_hashtable(10000);
    CXTranslationUnit tu=clang_createTranslationUnitFromSourceFile(idx,sourceFile,subArgc,subArgv,0,0);
    if(0==tu){
        fprintf(stderr,"%s: cannot create the translation unit.",pname);
        return(1);}
    CXCursor tucursor=clang_getTranslationUnitCursor(tu);
    // register_cursors(cursors,tucursor);
    // check_cursor_present(cursors,tucursor);
    /* hashtable_map(cursors,print_registered_cursor,0); */
    /* printf("\n"); */

    // print_cursor(clang_getTranslationUnitCursor(tu),0);

    printf("\n");
    clang_disposeTranslationUnit(tu);

    return(0);}



//// tests

int test_primes[]={
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
    67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
    139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
    223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
    293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
    383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461,
    463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563,
    569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
    647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739,
    743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
    839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
    941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021};

#define testing(BODY)                                                   \
    do{                                                                 \
        printf("%-40s ",__FUNCTION__);                                  \
        fflush(stdout);                                                 \
        { BODY }                                                        \
          printf(" [OK]\n");                                            \
          fflush(stdout);                                               \
    } while(0)


void test_compute_primes_to(void){
    testing({
                 int count=sizeof(test_primes)/sizeof(test_primes[0]);
                 id primes=compute_primes_to(1024);
                 assert(vector_length(primes)==count);
                 for(int i=0;i<count;i++){
                     assert(vector_get_int(primes,i)==test_primes[i]);}
             });}


void test_ceiling_to_nearest_prime(void){
    testing({
                 int count=sizeof(test_primes)/sizeof(test_primes[0]);
                 for(int i=1;i<count;i++){
                     int n=test_primes[i]-1;
                     int ceiling=ceiling_to_nearest_prime(n);
                     unless_assert(ceiling==test_primes[i],fprintf(stderr,"n=%d, expected=%d, got=%d\n",n,test_primes[i],ceiling););}
             });}


void test_box(void){
    testing({
                 CXCursor c=clang_getNullCursor();
                 id bc=box(ot_CXCursor,c);
                 assert(ot_CXCursor==type_of(bc));
                 assert(clang_Cursor_isNull(bc->value.cursor));

                 id bi=box(ot_int,42);
                 assert(ot_int==type_of(bi));
                 assert(42==bi->value.integer);

                 id bx=box(ot_char,'a');
                 assert(ot_char==type_of(bx));
                 assert('a'==bx->value.character);

                 cons_t* k=make_cons_t(bi,bx);
                 id bk=box(ot_cons,k);
                 assert(ot_cons==type_of(bk));
                 assert(k==bk->value.cons);

                 vector_t* v=unbox_vector(make_vector(ot_int,4,0,0));
                 id bv=box(ot_vector,v);
                 assert(ot_vector==type_of(bv));
                 assert(v==bv->value.vector);

                 hashtable* h=unbox_hashtable(make_hashtable(42));
                 id bh=box(ot_hashtable,h);
                 assert(ot_hashtable==type_of(bh));
                 assert(h==bh->value.hashtable);
             });}



void test_cons(void){
    testing({
                 assert(null(nil));

                 id c=cons(integer(42),nil);
                 assert(ot_cons==type_of(c));
                 assert(ot_int==type_of(car(c)));
                 assert(42==unbox_integer(car(c)));
                 assert(null(cdr(c)));

                 setcdr(c,character('B'));
                 assert(ot_cons==type_of(c));
                 assert(ot_int==type_of(car(c)));
                 assert(42==unbox_integer(car(c)));
                 assert(ot_char==type_of(cdr(c)));
                 assert('B'==unbox_character(cdr(c)));

                 id nc=cons(nil,nil);
                 setcar(c,nc);
                 assert(ot_cons==type_of(c));
                 assert(nc==car(c));
                 assert(ot_char==type_of(cdr(c)));
                 assert('B'==unbox_character(cdr(c)));

             });}


void test_list(void){
    testing({
                 id l=list(0);
                 assert(null(l));

                 l=list(1,integer(42));
                 assert(consp(l));
                 assert(equal(integer(42),car(l)));
                 assert(null(cdr(l)));

                 l=list(2,integer(33),integer(42));
                 assert(consp(l));
                 assert(equal(integer(33),car(l)));
                 assert(equal(integer(42),car(cdr(l))));
                 assert(null(cdr(cdr(l))));

                 l=list(3,integer(24),integer(33),integer(42));
                 assert(consp(l));
                 assert(equal(integer(24),car(l)));
                 assert(equal(integer(33),car(cdr(l))));
                 assert(equal(integer(42),car(cdr(cdr(l)))));
                 assert(null(cdr(cdr(cdr(l)))));
             });}


void test_reverse(void){
    testing({
                 id l=list(0);
                 id r=reverse(l);
                 assert(null(r));

                 l=list(1,integer(42));
                 r=reverse(l);
                 assert(consp(r));
                 assert(equal(integer(42),car(r)));
                 assert(null(cdr(r)));
                 assert(equal(l,r));

                 l=list(2,integer(33),integer(42));
                 r=reverse(l);
                 assert(consp(r));
                 assert(equal(integer(42),car(r)));
                 assert(equal(integer(33),car(cdr(r))));
                 assert(null(cdr(cdr(r))));

                 l=list(3,integer(24),integer(33),integer(42));
                 r=reverse(l);
                 assert(consp(r));
                 assert(equal(integer(42),car(r)));
                 assert(equal(integer(33),car(cdr(r))));
                 assert(equal(integer(24),car(cdr(cdr(r)))));
                 assert(null(cdr(cdr(cdr(r)))));
             });}


void test_revappend(void){
    testing({
                 id l=list(0);
                 id t=list(2,integer(3),integer(4));
                 id r=revappend(l,t);
                 assert(equal(r,t));

                 l=list(2,integer(2),integer(1));
                 r=revappend(l,t);
                 assert(consp(r));
                 assert(equal(r,list(4,integer(1),integer(2),integer(3),integer(4))));

                 l=list(3,integer(24),integer(33),integer(42));
                 r=revappend(l,nil);
                 assert(equal(r,reverse(l)));
             });}



void dump_hashtable(id table){
    fprintf(stderr,"size             = %d\n",hashtable_size(table));
    fprintf(stderr,"count            = %d\n",hashtable_count(table));
    fprintf(stderr,"rehash_size      = %f\n",hashtable_rehash_size(table));
    fprintf(stderr,"rehash_threshold = %f\n",hashtable_rehash_threshold(table));}

void test_hashtable(void){
    testing({
                 id table=make_hashtable(3);
                 assert(0==hashtable_count(table));
                 assert(3==hashtable_size(table));
             });}

void test_hashtable_set_grow(void){
    testing({
                 id table=make_hashtable(3);
                 assert(0==hashtable_count(table));
                 assert(3==hashtable_size(table));

                 hashtable_set(table,integer(65),character('A'));
                 assert(1==hashtable_count(table));
                 assert(3==hashtable_size(table));
                 assert(equal(character('A'),hashtable_get(table,integer(65))));

                 hashtable_set(table,integer(66),character('B'));
                 assert(2==hashtable_count(table));
                 assert(3==hashtable_size(table));
                 assert(equal(character('B'),hashtable_get(table,integer(66))));

                 hashtable_set(table,integer(67),character('C'));
                 assert(3==hashtable_count(table));
                 assert(5==hashtable_size(table));
                 assert(equal(character('C'),hashtable_get(table,integer(67))));

             });}


void test_hashtable_reset(void){
    testing({
                 id table=make_hashtable(3);
                 assert(0==hashtable_count(table));
                 assert(3==hashtable_size(table));

                 hashtable_set(table,integer(65),character('A'));
                 assert(1==hashtable_count(table));
                 assert(3==hashtable_size(table));
                 assert(equal(character('A'),hashtable_get(table,integer(65))));

                 hashtable_set(table,integer(66),character('B'));
                 assert(2==hashtable_count(table));
                 assert(3==hashtable_size(table));
                 assert(equal(character('B'),hashtable_get(table,integer(66))));

                 hashtable_set(table,integer(65),character('Z'));
                 assert(2==hashtable_count(table));
                 assert(3==hashtable_size(table));
                 assert(equal(character('Z'),hashtable_get(table,integer(65))));

                 hashtable_set(table,integer(66),character('Y'));
                 assert(2==hashtable_count(table));
                 assert(3==hashtable_size(table));
                 assert(equal(character('Y'),hashtable_get(table,integer(66))));

             });}


void test_hashtable_map_function(id key,id value,void* data){
    char* hits=data;
    assert(ot_int==type_of(key));
    assert(ot_char==type_of(value));
    assert(unbox_integer(key)==unbox_character(value));
    hits[unbox_integer(key)]=unbox_character(value);}

void test_hashtable_map(void){
    testing({
                 id table=make_hashtable(3);
                 assert(0==hashtable_count(table));
                 assert(3==hashtable_size(table));

                 for(int i=65;i<95;i++){
                     hashtable_set(table,integer(i),character(i));}
                 char hits[128]={0};
                 hashtable_map(table,test_hashtable_map_function,hits);
                 for(int i=0;i<128;i++){
                     if((i<65) or (95<=i)){
                         assert(0==hits[i]);
                     }else{
                         assert(i==hits[i]);
                     }}});}


void test_hashtable_remove_function(id key,id value,void* data){
    id table=data;
    assert(ot_int==type_of(key));
    assert(ot_char==type_of(value));
    assert(unbox_integer(key)==unbox_character(value));
    int count=hashtable_count(table);
    assert(0<count);
    hashtable_remove(table,key);
    assert(hashtable_count(table)==count-1);}

void test_hashtable_fail_function(id key,id value,void* data){
    assert(false);}

void test_hashtable_remove(void){
    testing({
                 id table=make_hashtable(3);
                 assert(0==hashtable_count(table));
                 assert(3==hashtable_size(table));

                 for(int i=65;i<95;i++){
                     hashtable_set(table,integer(i),character(i));}

                 int size=hashtable_size(table);
                 hashtable_map(table,test_hashtable_remove_function,table);
                 assert(hashtable_size(table)==size);
                 assert(hashtable_count(table)==0);
                 hashtable_map(table,test_hashtable_fail_function,0);});}


void test_all(void){
    testing({
                 fprintf(stderr," ...\n");
                 test_compute_primes_to();
                 test_ceiling_to_nearest_prime();
                 test_box();
                 test_cons();
                 test_list();
                 test_reverse();
                 test_revappend();
                 test_hashtable();
                 test_hashtable_set_grow();
                 test_hashtable_reset();
                 test_hashtable_map();
                 test_hashtable_remove();
                 fprintf(stderr,"%-40s ",__FUNCTION__);
             });}


//// THE END ////
ViewGit