bind transformers test added by dieggsy on Tue Mar 5 17:13:30 2019

;; bind-test.scm 
;; ===========================================
;; Compile with csc bind-test.scm -L "$(pkgconf --libs gsl)"
(import (only chicken.foreign foreign-declare)
        bind)

;; (foreign-declare "

;; ")
(foreign-declare "
#include 
#include 
#include 
")

(include "bind-transformers.scm")
(bind-options default-renaming: ""
              foreign-transformer: gsl-arg-transformer*)

(bind-opaque-type cfile (c-pointer "FILE"))
(bind "cfile fopen(char *, char *)")
(bind "int fflush(cfile)")
(bind "cfile stdout")

(bind-opaque-type csl_vector (c-pointer "gsl_vector_int"))
(bind "int gsl_vector_int_get(csl_vector, size_t)")

(bind-opaque-type matrix (c-pointer "gsl_matrix_int"))
(bind-rename/pattern "^gsl-matrix-int" "gsl-matrix")
(bind "matrix gsl_matrix_int_alloc(size_t, size_t)")
;; (bind-rename "gsl_matrix_int_get" matrix-ref)
(bind "int gsl_matrix_int_get(matrix, size_t, size_t)")
(bind "int gsl_matrix_int_fscanf(cfile, matrix)")
(bind "int gsl_matrix_int_fprintf(cfile, matrix, char *)")
;; (bind-file* "wrap.c")
(bind "struct gsl_complex gsl_complex_rect(double, double)")
(bind "struct gsl_complex gsl_complex_add(struct gsl_complex, struct gsl_complex)")
(bind "struct gsl_vector_int_view gsl_matrix_int_diagonal(matrix);")
(bind "int gsl_vector_int_get(csl_vector, const size_t);")
(bind "void gsl_matrix_int_free(matrix);")

(bind* "size_t gsl_vector_size (csl_vector v) {" "return v->size;" "}")


(define f (fopen "data/p11-grid.txt" "r"))
(define m (gsl-matrix-alloc 20 20))
(print (gsl-matrix-fscanf f m))
(print (stdout))
(print (gsl-matrix-get m 0 19))
;; (print (gsl-matrix-diag m))
(print (gsl-complex-rect 1 2))
(print (gsl-complex-add 1+2i 3+4i))
(print (gsl-vector-int-get (gsl-matrix-diagonal m) 0))
(print (gsl-vector-size (gsl-matrix-diagonal m)))
(gsl-matrix-free m)

;; bind-transformers.scm
;; ===========================================

(import (only chicken.foreign foreign-declare)
        (only matchable match)
        (only srfi-4
              f64vector make-f64vector f64vector->list
              f32vector make-f32vector f32vector->list)
        bind)

(foreign-declare "#include ")

(foreign-declare "
gsl_complex f64_to_complex(double *arg) {
    return gsl_complex_rect(arg[0],arg[1]);
}
" )

(import-for-syntax bind-translator
                   (only chicken.pretty-print pp)
                   (only chicken.string conc)
                   (only chicken.irregex
                         irregex-search
                         irregex-match
                         irregex-match-substring)
                   (only chicken.format format)
                   (only srfi-1 any)
                   (only srfi-13 string-prefix?)
                   (only matchable match))

(begin-for-syntax
  (define debug (make-parameter #f))
  (debug #t)
  (when (debug)
    (print "===== compile-time"))
  ;; convert any foreign-lambda with a gsl-complex struct return-type,
  ;; and make it return a 2-element f64vector instead.
  (define (gsl-ret-transformer* x rename)

    (define (make-complex-ret-lambda fl args body vec make-vec vec->list )
      (let* ((argnames (map cadr args))
             ;; return-type -> void, add f64vector destination
             ;; argument, and cast to gsl-complex.
             (lambda-with-destination
              (bind-foreign-lambda*
               `(,fl
                 void                           ;; new return type
                 ,(cons `(,vec dest) args) ;; add destination arg
                 (stmt
                  (= "gsl_complex _z" ,body) ;; allocate, cast & assign
                  (= "dest[0]" "GSL_REAL(_z)")
                  (= "dest[1]" "GSL_IMAG(_z)")
                  ))
               rename))
             ;; allocate a f64vector and use it as desination
             (destination-wrapper
              `(lambda ,argnames
                 (,(rename 'let) ((destination (,make-vec 2)))
                  (,lambda-with-destination destination ,@argnames)
                  (apply make-rectangular (,vec->list destination))))))
        destination-wrapper))

    (match x
      ;; return-type is a gsl-complex, need to convert
      ((foreign-lambda* ('struct (? (cut irregex-search "^gsl_complex" <>) type)) args body)
       (cond ((string=? type "gsl_complex")
              (make-complex-ret-lambda foreign-lambda* args body
                                       'f64vector 'make-f64vector 'f64vector->list))
             ((string=? type "gsl_complex_float")
              (make-complex-ret-lambda foreign-lambda* args body
                                       'f32vector 'make-f32vector 'f32vector->list))
             (else (error "Unknown complex type" type))))
      ((foreign-lambda* ('struct (? (cut irregex-match "gsl_vector_\\w+_view" <>) type)) args body)
       (let* ((argnames (map cadr args))
              (pref (irregex-match-substring
                     (irregex-match "(gsl_vector(_\\w+)?)_view" type)
                     1))
              (lambda-with-destination
               (bind-foreign-lambda*
                `(,foreign-lambda*
                     csl_vector ;; new return type
                     ,args
                   (stmt
                    (= ,(format "~a view" type) ,body) ;; allocate, cast & assign
                    ,(format "~a *vec = ~a_alloc(view.vector.size);" pref pref)
                    ,(format "memcpy(vec,&view.vector,sizeof(~a));" pref)
                    (return vec)))
                rename)))
         lambda-with-destination))
      ;; ignore other return-types
      (else (bind-foreign-lambda* x rename))))

  (define (gsl-arg-transformer* x rename)
    (define (complex-type? type)
      (and (pair? type)
           (eq? (car type) 'struct)
           (irregex-search "^gsl_complex" (cadr type))
           ;; (equal? type '(struct "gsl_complex"))
           ))
    (match x
      ;; return-type is a gsl-complex, need to convert
      ((foreign-lambda* rtype (? (lambda (x) (any complex-type? (map car x))) args) body)
       (when (debug)
         (print "----LAMBDA:")
         (pp x)
         (print "=>"))
       (let ((argnames (map cadr args)))
         (define (type varname)
           (any (lambda (spec)
                  (and (eq? (cadr spec) varname)
                       (car spec))) args))
         (define (gsl-complex? type)
           (and (equal? type '(struct "gsl_complex"))))
         (define (gsl-complex->f64vector as)
           (if (gsl-complex? (car as))
               (list 'f64vector (cadr as))
               as))
         ;; recursively look for variables which reference arguments of
         ;; type struct and cast from f64vector to struct gsl-complex*.
         (define (dereference body)
           (if (list? body)
               (map dereference body)
               (if (and (symbol? body) (gsl-complex? (type body)))
                   (conc "f64_to_complex(" body ")")
                   body)))
         (let ((final-lambda
                `(lambda ,argnames
                   (,(gsl-ret-transformer*
                      `(,foreign-lambda* ,rtype
                           ,(map gsl-complex->f64vector args)
                         ,(dereference body))
                      rename)
                    ,@(map (lambda (x)
                             (if (gsl-complex? (type x))
                                 `(f64vector (exact->inexact (real-part ,x))
                                             (exact->inexact (imag-part ,x)))
                                 x))
                           argnames)))))
           (when (debug)
             (pp final-lambda))
           final-lambda)))
      (else
       (gsl-ret-transformer*
        x
        rename)
       )
      ))
  )

;; convert any arguments of type (struct "gsl-complex") to f64vectors,
;; and cast & dereference from C.