Added tests; started implemeting print_cursor.

Pascal J. Bourguignon [2013-01-31 01:20]
Added tests; started implemeting print_cursor.
Filename
Makefile
ast.c
bug.out
diff --git a/Makefile b/Makefile
index e1dde7e..65c9f6e 100644
--- a/Makefile
+++ b/Makefile
@@ -37,14 +37,20 @@ clean:


 CC=/opt/llvm/bin/clang -isysroot /
+CFLAGS=
+#CFLAGS=-v
+#CFLAGS=-fblocks
+# -I/opt/llvm/lib/clang/3.3/include
+LDFLAGS=-L/opt/llvm/lib -lclang
 ast:ast.c Makefile
-	@ true $(CC) -I. -g3 -ggdb3 -E -o /dev/stdout ast.c
-	@ $(CC) -I. -g3 -ggdb3 -o ast ast.c -L/opt/llvm/lib -lclang
+	@ true $(CC) $(CFLAGS) -I. -g3 -ggdb3 -E -o /dev/stdout ast.c
+	@ $(CC) $(CFLAGS) -I. -g3 -ggdb3 -o ast ast.c $(LDFLAGS)

 test-ast:ast
-	@ LD_LIBRARY_PATH=/opt/llvm/lib:$LD_LIBRARY_PATH ./ast example.c
+	@ LD_LIBRARY_PATH=/opt/llvm/lib:$LD_LIBRARY_PATH ./ast --test example.c

-# -I/opt/llvm/lib/clang/3.3/include
+run-ast:ast
+	@ LD_LIBRARY_PATH=/opt/llvm/lib:$LD_LIBRARY_PATH ./ast example.c

 #### THE END ####

diff --git a/ast.c b/ast.c
index a68e75f..cce0bd4 100644
--- a/ast.c
+++ b/ast.c
@@ -1,169 +1,99 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <string.h>
 #include <iso646.h>
 #include <clang-c/Index.h>
-#undef NDEBUG
-#include <assert.h>
+
+// Viva Greenspun's Tenth Law!
+

 typedef enum {false=0,true=1} bool;
 #define INCF(x) (++(x))
 #define DECF(x) (--(x))


+void* nil=0;

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


-void* memory_alloc(const char* fname,size_t size){
-    /*DEBUG*/printf("%s(%s,%zu)\n",__FUNCTION__,fname,size); fflush(stdout);
-    void* memory=malloc(size);
-    if(0==memory){
-        fprintf(stderr,"%s: out of memory\n",fname);
-        exit(1);}
-    return(memory);}
-
-
-int* compute_primes_to(int n){
-    /*DEBUG*/printf("%s(%d)\n",__FUNCTION__,n); fflush(stdout);
-    if(n<2){
-        int* primes=memory_alloc(__FUNCTION__,1);
-        primes[0]=0;
-        return(primes);
-    }else if(2==n){
-        int* primes=memory_alloc(__FUNCTION__,2);
-        primes[0]=1;
-        primes[1]=2;
-        return(primes);
-    }else if(3==n){
-        int* primes=memory_alloc(__FUNCTION__,3);
-        primes[0]=1;
-        primes[1]=2;
-        primes[2]=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;
-        int* primes;
-
-        n-=(n%1)?3:2;
-        bits_max=n/2;
-        words_max=(bits_max+word_size-1)/word_size;
-        bits=memory_alloc(__FUNCTION__,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);
-        primes=memory_alloc(__FUNCTION__,(1+prime_count)*sizeof(int));
-        primes[0]=prime_count;
-        int curnum=1;
-        primes[curnum++]=2;
-        primes[curnum++]=3;
-        cur_prime=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;
-            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);}}
-
-
-
-int* primes=0;
+#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)

-int ceiling_to_nearest_prime(int n){
-    /*DEBUG*/printf("%s(%d)\n",__FUNCTION__,n); fflush(stdout);
-    if((0==primes) or (primes[primes[0]-1]<n)){
-        primes=compute_primes_to(n*2);
-    }
-    int min=1;
-    int max=primes[0];
-    int ind=(min+max)/2;
-    int ord=(n==primes[ind])?0:(n<primes[ind])?-1:1;
-    while((0!=ord) and (min!=ind)){
-        if(ord<0){
-            max=ind;
-        }else{
-            min=ind;
-        }
-        ind=(min+max)/2;
-        ord=(n==primes[ind])?0:(n<primes[ind])?-1:1;}
-    if((1<ind)and(ord<0)){
-        ord=1;
-        ind--;}
-    if(ord<0){
-        return(primes[1]);
-    }else{
-        return(primes[ind+1]);
-    }}
+#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);}

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

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

-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_alloc(__FUNCTION__,(1+cnt1+cnt2)*sizeof(char*));
-    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);}



 typedef enum {
     ot_nil=0,
-    ot_CXCursor,  // CXCursor*
-    ot_int,       // int
-    ot_cons,      // cons*
-    ot_hashtable, // hashtable*
+    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("null");
-      case ot_CXCursor: return("CXCursor");
-      case ot_int: return("integer");
-      case ot_cons: return("cons");
+      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: return("#<UNKNOWN TYPE>");}}
+      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",
@@ -174,37 +104,66 @@ void error_signal(const char* fname,const char* message){
     fprintf(stderr,"%s: %s\n",fname,message);
     exit(1);}

-typedef struct {
+
+
+typedef struct object {
     object_type type;
     union {
         CXCursor cursor;
-        struct hashtable* hashtable;
-        struct cons* cons;
         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,...){
-    /*DEBUG*/printf("%s(%s,…)\n",__FUNCTION__,type_name(type)); fflush(stdout);
-    object* o=memory_alloc(__FUNCTION__,sizeof(*o));
+    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_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);}


-void* nil=0;
+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);}
+
+
+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 null(void* object){
-    return(0==object);}
+
+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);}



@@ -213,11 +172,14 @@ typedef struct cons {
     object* cdr;
 } kons;

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

 object* car(object* cell){
     if(0==cell){ return(cell); }
@@ -241,19 +203,154 @@ object* setcdr(object* cell,object* d){



+
+typedef struct vector {
+    object_type element_type;
+    int size;
+    int fill_pointer;
+    char* data;
+} 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 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->type==b->type){
+    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_hashtable: return(a->value.hashtable==b->value.hashtable);}
+          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;
@@ -262,6 +359,23 @@ typedef struct hashtable {
     object** entries;
 } 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){
@@ -269,40 +383,82 @@ unsigned sxhash(object* o){
       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_hashtable: return(hashtable_hash(o->value.hashtable));}}
+      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){
-    hashtable* h=memory_alloc(__FUNCTION__,sizeof(*h));
+    if(null(hashtable_deleted_entry)){
+        hashtable_deleted_entry=cons(nil,nil);}
+    hashtable* h=memory_allocate(__FUNCTION__,sizeof(*h),1);
     h->count=0;
-    h->size=size;
+    h->size=primep(size)?size:ceiling_to_nearest_prime(1+size);
     h->rehash_size=2.0;
     h->rehash_threshold=1.5;
-    h->entries=memory_alloc(__FUNCTION__,sizeof(*(h->entries))*size);
+    h->entries=memory_allocate(__FUNCTION__,sizeof(*(h->entries)),h->size);
     int i=0;
-    for(i=0;i<size;i++){
+    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(key,table->entries[i]->value.cons->car))){
+    while(not(null(table->entries[i]))
+          and not(equal(car(table->entries[i]),key))){
         i=(i+1)%table->size;}
     return(cdr(table->entries[i]));}

-unsigned hashtable_hash(hashtable* table){
-    return((table->size<<3)+table->count);}
+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_alloc(__FUNCTION__,newsize);
+    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(entry){
+        if(not(null(entry) or hashtable_entry_deleted_p(entry))){
             unsigned h=sxhash(car(entry));
             int j=h%newsize;
             while(not(null(newentries[j]))){
@@ -313,24 +469,177 @@ hashtable* hashtable_grow(hashtable* table){
     return(table);}

 object* hashtable_set(hashtable* table,object* key,object* value){
-    if(table->count*table->rehash_size<table->size){
-        unsigned hash=sxhash(key);
-        int i=hash%table->size;
-        while(not(null(table->entries[i])) and not(equal(key,car(table->entries[i])))){
-            i=(i+1)%table->size;}
-        if(null(table->entries[i])){
+    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{
-            setcdr(table->entries[i],value);
+            min=ind;
         }
-        return(value);
+        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{
-        hashtable_grow(table);
-        return(hashtable_set(table,key,value));}}
+        return(vector_get_int(primes,1+ind));
+    }}
+



+//// 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){
@@ -484,6 +793,7 @@ const char* cursorSymbol(int cursorKind){
       default:                                          return ":invalid";}}


+
 const char* cursorLinkage(int linkageKind){
     switch(linkageKind){
       case CXLinkage_NoLinkage:      return ":no-linkage";
@@ -502,64 +812,1010 @@ const char* cursorLanguageKind(int languageKind){
       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 */
+/* } */
+
+
+void print_string(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_string(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_string_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_string_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_string(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);}
+
+
+enum CXChildVisitResult register_visitor(CXCursor cursor,CXCursor parent,CXClientData client_data){
+    hashtable* table=client_data;
+    object* c=box(ot_CXCursor,cursor);
+    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(cursor));
+    assert(clang_hashCursor(c->value.cursor)==clang_hashCursor(cursor_value(c)));
+    object* n=hashtable_get(table,c);
+    if(nil==n){
+        hashtable_set(table,c,cons(integer(hashtable_count(table)),integer(0)));
+        return(CXChildVisit_Recurse);
+    }else{
+        return(CXChildVisit_Continue);}}
+
+void register_cursors(hashtable* cursors,CXCursor rootCursor){
+    register_visitor(rootCursor,clang_getNullCursor(),cursors);
+    clang_visitChildren(rootCursor,register_visitor,cursors);}
+
+
+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){
-    test_all();
     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 cursor=clang_getTranslationUnitCursor(tu);
-    if(clang_Cursor_isNull(cursor)){
-        printf("nil\n");
-    }else{
-        printf("(%s",cursorSymbol(clang_getCursorKind(cursor)));
-        printf("\n :linkage %s",cursorLinkage(clang_getCursorLinkage(cursor)));
-        printf("\n :language-kind %s",cursorLanguageKind(clang_getCursorLanguage(cursor)));
-
-        CXSourceLocation location=clang_getCursorLocation(cursor);
-        CXFile file;
-        unsigned line;
-        unsigned column;
-        unsigned offset;
-
-        clang_getSpellingLocation(location,&file,&line,&column,&offset);
-        CXString fileName=clang_getFileName(file);
-        printf("\n :location (location :file \"%s\" :line %u :column %u :offset %u)",clang_getCString(fileName),line,column,offset);
-        clang_disposeString(fileName);
-
-        CXSourceRange range=clang_getCursorExtent(cursor);
-        CXSourceLocation start=clang_getRangeStart(range);
-        CXSourceLocation end=clang_getRangeEnd(range);
-
-        clang_getSpellingLocation(start,&file,&line,&column,&offset);
-        fileName=clang_getFileName(file);
-        printf("\n :range (range :start (location :file \"%s\" :line %u :column %u :offset %u)",clang_getCString(fileName),line,column,offset);
-        clang_disposeString(fileName);
-
-        clang_getSpellingLocation(end,&file,&line,&column,&offset);
-        fileName=clang_getFileName(file);
-        printf("\n               :end   (location :file \"%s\" :line %u :column %u :offset %u))",clang_getCString(fileName),line,column,offset);
-        clang_disposeString(fileName);
-
-
-
-
-        printf(")\n");
-    }
+    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);}


@@ -567,7 +1823,6 @@ int main(int argc,const char* const* argv){
 //// tests

 int test_primes[]={
-    172,
     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,
@@ -583,34 +1838,225 @@ int test_primes[]={

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


 void test_compute_primes_to(void){
     testing({
-                 int* primes=compute_primes_to(1024);
-                 for(int i=0;i<=test_primes[0];i++){
-                     assert(test_primes[i]==primes[i]);}
+                 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({
-                 for(int i=1;i<test_primes[0];i++){
+                 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);
-                     assert(ceiling==test_primes[i]);}
+                     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 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_hashtable();
+                 test_hashtable_set_grow();
+                 test_hashtable_reset();
+                 test_hashtable_map();
+                 test_hashtable_remove();
+                 fprintf(stderr,"%-40s ",__FUNCTION__);
              });}


diff --git a/bug.out b/bug.out
new file mode 100644
index 0000000..811e67d
--- /dev/null
+++ b/bug.out
@@ -0,0 +1,77 @@
+                #1510=(:typedef-decl
+                     :is-declaration t
+                     :is-reference nil
+                     :is-expression nil
+                     :is-statement nil
+                     :is-attribute nil
+                     :is-invaild nil
+                     :is-translation-unit nil
+                     :is-preprocessing nil
+                     :is-unexposed nil
+                     :linkage :no-linkage
+                     :language :c
+                     :translation-unit #0#
+                     :semantic-parent #0#
+                     :lexical-parent #0#
+                     :location (location :file nil :line 0 :column 0 :offset 0)
+                     :range (range :start (location :file nil :line 0 :column 0 :offset 0)
+                                   :end   (location :file nil :line 0 :column 0 :offset 0))
+                     :type :Typedef
+                     :underlying-type :Constant-Array
+                     :enum-type :Invalid
+                     :enum-constant -9223372036854775808
+                     :unsigned-enum-constant 18446744073709551615
+                     :definition #1510#
+                     :is-definition t
+                     :canonical #1510#
+                     :children (#1511=(:type-ref
+                                     :is-declaration nil
+                                     :is-reference t
+                                     :is-expression nil
+                                     :is-statement nil
+                                     :is-attribute nil
+                                     :is-invaild nil
+                                     :is-translation-unit nil
+                                     :is-preprocessing nil
+                                     :is-unexposed nil
+                                     :linkage :invalid
+                                     :language :invalid
+                                     :translation-unit #0#
+                                     :semantic-parent nil
+                                     :lexical-parent nil
+                                     :location (location :file nil :line 0 :column 0 :offset 0)
+                                     :range (range :start (location :file nil :line 0 :column 0 :offset 0)
+                                                   :end   (location :file nil :line 0 :column 0 :offset 0))
+                                     :type :Typedef
+                                     :underlying-type :Invalid
+                                     :enum-type :Invalid
+                                     :enum-constant -9223372036854775808
+                                     :unsigned-enum-constant 18446744073709551615
+                                     :definition (:typedef-decl
+                                                   :is-declaration t
+                                                   :is-reference nil
+                                                   :is-expression nil
+                                                   :is-statement nil
+                                                   :is-attribute nil
+                                                   :is-invaild nil
+                                                   :is-translation-unit nil
+                                                   :is-preprocessing nil
+                                                   :is-unexposed nil
+                                                   :linkage :no-linkage
+                                                   :language :c
+                                                   :translation-unit #0#
+                                                   :semantic-parent #0#
+                                                   :lexical-parent #0#
+                                                   :location (location :file nil :line 0 :column 0 :offset 0)
+                                                   :range (range :start (location :file nil :line 0 :column 0 :offset 0)
+                                                                 :end   (location :file nil :line 0 :column 0 :offset 0))
+                                                   :type :Typedef
+                                                   :underlying-type :Record
+                                                   :enum-type :Invalid
+                                                   :enum-constant -9223372036854775808
+                                                   :unsigned-enum-constant 18446744073709551615
+                                                   :definition (:typedef-decl
+                                                             :is-declaration t
+                                                             :is-reference nil
+                                                             :is-expression nil
+                                                             :is-statement nil
ViewGit