#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) \
    ({ object* 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);})


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

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

#define assert(EXPRESSION) ASSERT_INTERNAL(EXPRESSION)
#define unless_assert(EXPRESSION,BODY) UNLESS_ASSERT_INTERNAL(EXPRESSION,BODY)

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


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);}





void* nil=0;

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


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(!"Unknown 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(!"Unknown type");}}


void error_type(const char* fname,object_type expected,object_type got){
    fprintf(stderr,"%s: got an object of type %s, expected type %s\n",
            fname,type_name(got),type_name(expected));
    exit(1);}

void error_signal(const char* fname,const char* message){
    fprintf(stderr,"%s: %s\n",fname,message);
    exit(1);}




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

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

object* box(object_type type,...){
    object* 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_signal(__FUNCTION__,"unexpected object type.");        break;}
    va_end(ap);
    return(o);}


bool cursorp(object* x){
    return(not(null(x)) and (ot_CXCursor==type_of(x)));}

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

CXCursor cursor_value(object* o){
    assert(nil!=o);
    assert(ot_CXCursor==type_of(o));
    return(o->value.cursor);}


bool integerp(object* x){
    return(not(null(x)) and (ot_int==type_of(x)));}

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

int integer_value(object* o){
    assert(nil!=o);
    assert(ot_int==type_of(o));
    return(o->value.integer);}


bool characterp(object* x){
    return(not(null(x)) and (ot_char==type_of(x)));}

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

char character_value(object* o){
    assert(nil!=o);
    assert(ot_char==type_of(o));
    return(o->value.character);}



typedef struct cons {
    object* car;
    object* cdr;
} kons;

kons* make_kons(object* a,object* d){
    kons* cell=memory_allocate(__FUNCTION__,sizeof(*cell),1);
    cell->car=a;
    cell->cdr=d;
    return(cell);}

bool consp(object* a){
    return(not(null(a)) and (ot_cons==type_of(a)));}

kons* cons_value(object* o){
    assert(nil!=o);
    assert(ot_cons==type_of(o));
    return(o->value.cons);}

object* cons(object* a,object* d){
    return(box(ot_cons,make_kons(a,d)));}

object* car(object* cell){
    if(0==cell){ return(cell); }
    else if(ot_cons==cell->type){ return(cell->value.cons->car); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}

object* cdr(object* cell){
    if(0==cell){ return(cell); }
    else if(ot_cons==cell->type){ return(cell->value.cons->cdr); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}

object* setcar(object* cell,object* a){
    if(0==cell){ error_type(__FUNCTION__,ot_cons,ot_nil); return(nil); }
    else if(ot_cons==cell->type){ cell->value.cons->car=a; return(a); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}

object* setcdr(object* cell,object* d){
    if(0==cell){ error_type(__FUNCTION__,ot_cons,ot_nil); return(nil); }
    else if(ot_cons==cell->type){ cell->value.cons->cdr=d; return(d); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}

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

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

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

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

object* last   (object* list){
    while(cdr(list)){
        list=cdr(list);}
    return(list);}

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

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


int length(object* list){
    int n=0;
    while(consp(list)){
        list=cdr(list);
        n++;}
    return(n);}

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

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

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

object* reverse(object* list){
    return(reverse_accumulator(list,nil));}

object* revappend(object* list,object* tail){
    return(reverse_accumulator(list,tail));}

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

object* nreverse(object* list){
    return(nreconc(list,nil));}

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

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


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

bool vectorp(object* x){
    return(not(null(x)) and (ot_vector==type_of(x)));}

vector* vector_value(object* o){
    assert(nil!=o);
    assert(ot_vector==type_of(o));
    return(o->value.vector);}

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

vector* 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* 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(v);}


object_type vector_element_type(vector* v){
    assert(nil!=v);
    return(v->element_type);}

int vector_size(vector* v){
    assert(nil!=v);
    return(v->size);}

int vector_fill_pointer(vector* v){
    assert(nil!=v);
    return(v->fill_pointer);}

vector* vector_set_fill_pointer(vector* v,int fill_pointer){
    assert(nil!=v);
    assert(0<=fill_pointer);
    assert(fill_pointer<=v->size);
    v->fill_pointer=fill_pointer;
    return(v);}

int vector_length(vector* v){
    return(vector_fill_pointer(v));}


vector* vector_set_data(vector* 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);}

vector* vector_set_char(vector* v,int index,char data){
    assert(nil!=v);
    assert(ot_char==v->element_type);
    return(vector_set_data(v,index,&data));}

vector* vector_set_int(vector* v,int index,int data){
    assert(nil!=v);
    assert(ot_int==v->element_type);
    return(vector_set_data(v,index,&data));}

vector* vector_set(vector* v,int index,object* object){
    assert(nil!=v);
    assert(ot_t==v->element_type);
    return(vector_set_data(v,index,&object));}


void* vector_get_data(vector* 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(vector* v,int index){
    assert(nil!=v);
    assert(ot_char==v->element_type);
    char result;
    memcpy(&result,vector_get_data(v,index),sizeof(char));
    return(result);}

int vector_get_int(vector* v,int index){
    assert(nil!=v);
    assert(ot_int==v->element_type);
    int result;
    memcpy(&result,vector_get_data(v,index),sizeof(int));
    return(result);}

object* vector_get(vector* v,int index){
    assert(nil!=v);
    assert(ot_t==v->element_type);
    object* result;
    memcpy(&result,vector_get_data(v,index),sizeof(object*));
    return(result);}


bool stringp(object* x){
    return(not(null(x)) and (ot_vector==type_of(x))
           and (ot_char==vector_element_type(vector_value(x))));}

object* string(const char* text){
    int len=strlen(text);
    vector* v=make_vector(ot_char,len,len,0);
    for(int i=0;i<len;i++){
        vector_set_char(v,i,text[i]);}
    return(box(ot_vector,v));}

bool string_equal(vector* a,vector* b){
    if((vector_element_type(a)!=vector_element_type(b))
       or (ot_char!=vector_element_type(a))
       or (vector_fill_pointer(a)!=vector_fill_pointer(b))){
        return(false);
    }
    for(int i=0;i<vector_fill_pointer(a);i++){
        if(vector_get_char(a,i)!=vector_get_char(b,i)){
            return(false);}}
    return(true);}

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


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



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

bool hashtablep(object* x){
    return(not(null(x)) and (ot_hashtable==type_of(x)));}

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

int hashtable_count(hashtable* table){
    assert(nil!=table);
    return(table->count);}

int hashtable_size(hashtable* table){
    assert(nil!=table);
    return(table->size);}

float hashtable_rehash_size(hashtable* table){
    assert(nil!=table);
    return(table->rehash_size);}

float hashtable_rehash_threshold(hashtable* table){
    assert(nil!=table);
    return(table->rehash_threshold);}


unsigned hashtable_hash(hashtable*);

unsigned sxhash(object* 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==vector_element_type(o->value.vector))
                                ?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);

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

hashtable* 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(h);}

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


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

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

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

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


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

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


vector* 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){
        vector* primes=make_vector(ot_int,1,1,&zero);
        vector_set_int(primes,0,2);
        return(primes);
    }else if(3==n){
        vector* 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);
        vector* 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);}}



vector* 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));
    }}






object* prin1_object(object* object,FILE* file);
object* print_list(object* 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);}


object* print_string(object* object,FILE* file){
    fprintf(file,"\"");
    vector* v=vector_value(object);
    int count=vector_length(v);
    for(int i=0;i<count;i++){
        char ch=vector_get_char(v,i);
        if(('"'==ch)or('\\'==ch)){
            fprintf(file,"\\%c",ch);
        }else{
            fprintf(file,"%c",ch);}}
    fprintf(file,"\"");
    return(object);}


object* print_vector(object* object,FILE* file){
    vector* v=vector_value(object);
    int count=vector_length(v);
    const char* sep="";
    switch(vector_element_type(v)){
      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(v,i));
              sep=" ";}
          fprintf(file,")");
          break;
      case ot_t:
          fprintf(file,"#(");
          for(int i=0;i<count;i++){
              prin1_object(vector_get(v,i),file);
              sep=" ";}
          fprintf(file,")");
          break;
      default:
          fprintf(file,"#<vector>");
          break;
    }
    return(object);}


object* prin1_object(object* 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",integer_value(object));
              break;
          case ot_char:
              fprintf(file,"#\%c",character_value(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(hashtable_value(object)));
              break;
          default:
              fprintf(file,"#<OBJECT-OF-UNKNOWN-TYPE>");
              break;
        }}
    return(object);}



//// arguments

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

static const char* Includes[]={"-I/opt/llvm/lib/clang/3.3/include",0};

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 */
/* } */


object* cxstring(CXString theCXString){
    const char* cstring=clang_getCString(theCXString);
    object* 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(")");}


hashtable* cursors=0;
// maps CXCursor objects to integer objects.

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;}}


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

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

void print_cursor(CXCursor cxcursor,int margin);


typedef struct {
    int margin;
    bool first;
} margin_closure;


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{
        object* 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(1==integer_value(cdr(pair))){
            printf("#%d#",integer_value(car(pair)));
        }else{
            int kind=clang_getCursorKind(cxcursor);
            printf("#%d=(%s",integer_value(car(pair)),cursorSymbol(kind));
            setcdr(pair,integer(1));
            print_slots(cxcursor,kind,margin+4);//TODO: width of #nn=
            printf(")");}}}


void print_registered_cursor(object* cursor,object* pair,void* data){
    printf("\n#%d=",integer_value(car(pair)));
    print_cursor(cursor_value(cursor),0);}




typedef struct {
    // IN:
    hashtable* visited; // maps cursors to (#n# visited-0/1 linkedCursors)
    // OUT:
    object*    linkedCursors;
} visit_cursor_closure;


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

    object* c=box(ot_CXCursor,cxcursor);
    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(cxcursor));
    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(cursor_value(c)));
    object* n=hashtable_get(visited,c);
    if(null(n)){
        object* 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){
            object* 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){
            object* 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_cursor_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(object* key,object* value,void* data){
    present_closure* closure=data;
    assert(ot_CXCursor==type_of(key));
    INCF(closure->counter);
    bool areEqual=clang_equalCursors(cursor_value(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(cursor_value(key),closure->cxcursor)){
        assert(clang_hashCursor(cursor_value(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];
    if(argc<2){
        fprintf(stderr,"%s: missing source file argument.\n",pname);
        return(1);}

    const char* sourceFile=argv[1];
    if(0==strcmp(sourceFile,"--test")){
        test_all();
        INCF(argv);
        DECF(argc);
        sourceFile=argv[1];
    }
    argv+=2;
    argc-=2;
    const char* const* subArgv=argv_concat(Includes,argv);
    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]);
                 vector* 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();
                 object* bc=box(ot_CXCursor,c);
                 assert(ot_CXCursor==type_of(bc));
                 assert(clang_Cursor_isNull(bc->value.cursor));

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

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

                 kons* k=make_kons(bi,bx);
                 object* bk=box(ot_cons,k);
                 assert(ot_cons==type_of(bk));
                 assert(k==bk->value.cons);

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

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



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

                 object* c=cons(integer(42),nil);
                 assert(ot_cons==type_of(c));
                 assert(ot_int==type_of(car(c)));
                 assert(42==integer_value(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==integer_value(car(c)));
                 assert(ot_char==type_of(cdr(c)));
                 assert('B'==character_value(cdr(c)));

                 object* 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'==character_value(cdr(c)));

             });}


void test_list(void){
    testing({
                 object* 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({
                 object* l=list(0);
                 object* 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({
                 object* l=list(0);
                 object* t=list(2,integer(3),integer(4));
                 object* 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(hashtable* 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({
                 hashtable* table=make_hashtable(3);
                 assert(0==hashtable_count(table));
                 assert(3==hashtable_size(table));
             });}

void test_hashtable_set_grow(void){
    testing({
                 hashtable* 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({
                 hashtable* 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(object* key,object* value,void* data){
    char* hits=data;
    assert(ot_int==type_of(key));
    assert(ot_char==type_of(value));
    assert(integer_value(key)==character_value(value));
    hits[integer_value(key)]=character_value(value);}

void test_hashtable_map(void){
    testing({
                 hashtable* 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(object* key,object* value,void* data){
    hashtable* table=data;
    assert(ot_int==type_of(key));
    assert(ot_char==type_of(value));
    assert(integer_value(key)==character_value(value));
    int count=hashtable_count(table);
    assert(0<count);
    hashtable_remove(table,key);
    assert(hashtable_count(table)==count-1);}

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

void test_hashtable_remove(void){
    testing({
                 hashtable* 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