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.