|
From: Akshay S. <ak...@us...> - 2012-07-22 17:03:49
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "matlisp".
The branch, tensor has been updated
via 3d2b1c49901f857eff0b30ebecaeb251d35e1755 (commit)
via aa67585771f77454b95fa7b16767ef3a6ff03923 (commit)
via 00e53dd09b3cc988dcd4e6e82934ff78bcb83501 (commit)
via 1ab6cec8e17077b9533560c9a5bc010e95818a04 (commit)
via b6be337cd4bfc4e869cc13317e36244517fb95a8 (commit)
via 4022a66033df8820d07bb2abd81b9a355274bd71 (commit)
via 77cde81e39386e147ac35c488d1f7c581d7bd9b8 (commit)
via c73c3a034c2a655afb2edd38ed6f0dcef6050b3d (commit)
via c2b5936d4d517cf0a7ee3e8d4a5d9b683249076c (commit)
from d18665bf3b836e17d2ff75065b384b5ff07059e3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 3d2b1c49901f857eff0b30ebecaeb251d35e1755
Author: Akshay Srinivasan <aks...@gm...>
Date: Sun Jul 22 22:28:13 2012 +0530
o Renamed non-exported functions in f77-ffi.lisp to avoid name clobbering (working on the C-FFI, see).
o Added some documentation to some exotic macros in utilities.lisp
diff --git a/matlisp.asd b/matlisp.asd
index 9c6076b..be38acc 100644
--- a/matlisp.asd
+++ b/matlisp.asd
@@ -77,7 +77,7 @@
:components ((:file "ffi-cffi")
(:file "ffi-cffi-implementation-specific")
(:file "foreign-vector")
- (:file "fortran-ffi"
+ (:file "f77-ffi"
:depends-on ("ffi-cffi"
"ffi-cffi-implementation-specific"
"foreign-vector"))
diff --git a/packages.lisp b/packages.lisp
index 8767417..b295a79 100644
--- a/packages.lisp
+++ b/packages.lisp
@@ -77,7 +77,7 @@
#:when-let #:if-let #:if-ret #:with-gensyms #:let-rec
#:mlet* #:make-array-allocator #:let-typed
#:nconsc #:define-constant
- #:macrofy
+ #:macrofy #:looped-mapcar
;;
#:inlining #:definline
#:with-optimization #:quickly #:very-quickly #:slowly #:quickly-if))
diff --git a/src/ffi/f77-ffi.lisp b/src/ffi/c-ffi.lisp
similarity index 95%
copy from src/ffi/f77-ffi.lisp
copy to src/ffi/c-ffi.lisp
index 9c5491f..7a6fba9 100644
--- a/src/ffi/f77-ffi.lisp
+++ b/src/ffi/c-ffi.lisp
@@ -1,46 +1,44 @@
;;; -*- Mode: lisp; Syntax: ansi-common-lisp; Package: :fortran-ffi-accessors; Base: 10 -*-
-;; Allowed types:
-;; :single-float :double-float
-;; :complex-single-float :complex-double-float
-;; :integer :long
-
-;; Callbacks : (:function <output-type> {(params)})
-
-;;TODO add declarations to generated wrappers.
(in-package #:matlisp-ffi)
-;: Don't blame us, a lot of useful code
-;; is written in that stilted language.
-(define-constant +f77-types+
- '(:single-float :double-float
- :complex-single-float :complex-double-float
- :integer :long
- :string
- :callback))
+(defmacro defccomplex (name base-type)
+ `(cffi:defcstruct ,name
+ (real ,base-type)
+ (imag ,base-type)))
+
+(defccomplex c-complex-double :double)
+(defccomplex c-complex-float :float)
;; Get the equivalent CFFI type.
;; If the type is an array, get the type of the array element type.
-(defun f77->cffi-type (type)
+(defun c->cffi-type (type)
"Convert the given Fortran FFI type into a type understood by CFFI."
(cond
((and (listp type) (eq (first type) '*))
- `(:pointer ,@(f77->cffi-type (second type))))
+ `(:pointer ,(c->cffi-type
+ (case (second type)
+ ;;CDR coding ?
+ (:complex-single-float :single-float)
+ (:complex-double-float :double-float)
+ (t (second type))))))
((callback-type-p type)
- `(:pointer ,@(f77->cffi-type :callback)))
+ `(:pointer ,(c->cffi-type :callback)))
((eq type :complex-single-float)
- `(:pointer ,@(f77->cffi-type :single-float)))
+ `(:struct c-complex-float))
((eq type :complex-double-float)
- `(:pointer ,@(f77->cffi-type :double-float)))
- (t `(,(ecase type
- (:void :void)
- (:integer :int)
- (:long :long)
- (:single-float :float)
- (:double-float :double)
- (:string :string)
- ;; Pass a pointer to the function.
- (:callback :void))))))
+ `(:struct c-complex-double))
+ (t (case type
+ (:void :void)
+ (:integer :int)
+ (:long :long)
+ (:single-float 'c-complex-float)
+ (:double-float 'c-complex-double)
+ (:string :string)
+ ;; Pass a pointer to the function.
+ (:callback :void)
+ ;;We assume the type is known to CFFI.
+ (t type)))))
;; Check if given type is a string
(declaim (inline string-p))
@@ -552,3 +550,4 @@
,(if (eq hack-return-type :void)
nil
retvar))))))))
+
diff --git a/src/ffi/f77-ffi.lisp b/src/ffi/f77-ffi.lisp
index 9c5491f..d68b04b 100644
--- a/src/ffi/f77-ffi.lisp
+++ b/src/ffi/f77-ffi.lisp
@@ -10,100 +10,96 @@
(in-package #:matlisp-ffi)
-;: Don't blame us, a lot of useful code
-;; is written in that stilted language.
-(define-constant +f77-types+
- '(:single-float :double-float
- :complex-single-float :complex-double-float
- :integer :long
- :string
- :callback))
-;; Get the equivalent CFFI type.
-;; If the type is an array, get the type of the array element type.
-(defun f77->cffi-type (type)
- "Convert the given Fortran FFI type into a type understood by CFFI."
- (cond
- ((and (listp type) (eq (first type) '*))
- `(:pointer ,@(f77->cffi-type (second type))))
- ((callback-type-p type)
- `(:pointer ,@(f77->cffi-type :callback)))
- ((eq type :complex-single-float)
- `(:pointer ,@(f77->cffi-type :single-float)))
- ((eq type :complex-double-float)
- `(:pointer ,@(f77->cffi-type :double-float)))
- (t `(,(ecase type
- (:void :void)
- (:integer :int)
- (:long :long)
- (:single-float :float)
- (:double-float :double)
- (:string :string)
- ;; Pass a pointer to the function.
- (:callback :void))))))
-
-;; Check if given type is a string
-(declaim (inline string-p))
-(defun string-p (type)
+(definline %f77.string-p (type)
+ "
+ Checks if the given type is a string."
(eq type :string))
-;; Check if given type is an array
-(declaim (inline array-p))
-(defun array-p (type)
+(definline %f77.array-p (type)
+ "
+ Checks if the given type is an array."
(and (listp type) (eq (car type) '*)))
-;; Check if the given type is - or has to be passed as - an array.
-(defun cast-as-array-p (type)
- (or (if (listp type)
- (eq (car type) '*))
+(definline %f77.cast-as-array-p (type)
+ "
+ Checks if the given type is - or has to be passed as - an array."
+ (or (when (listp type)
+ (eq (car type) '*))
(eq type :complex-single-float)
(eq type :complex-double-float)))
;; Check if the given type is a callback.
-(declaim (inline callback-type-p))
-(defun callback-type-p (type)
+(definline %f77.callback-type-p (type)
+ "
+ Checks if the given type is a callback"
(and (listp type) (eq (first type) :callback)))
-;; Fortran functions return-by-values.
-(defun get-return-type (type)
- (if (or (cast-as-array-p type) (callback-type-p type))
- (error "Cannot have a Fortran function output the type: ~S directly." type)
- (f77->cffi-type type)))
+;; Get the equivalent CFFI type.
+;; If the type is an array, get the type of the array element type.
+(defun %f77.cffi-type (type)
+ "Convert the given matlisp-ffi type into one understood by CFFI."
+ (cond
+ ((and (listp type) (eq (first type) '*))
+ `(:pointer ,(%f77.cffi-type (second type))))
+ ((%f77.callback-type-p type)
+ `(:pointer ,(%f77.cffi-type :callback)))
+ ((eq type :complex-single-float)
+ `(:pointer ,(%f77.cffi-type :single-float)))
+ ((eq type :complex-double-float)
+ `(:pointer ,(%f77.cffi-type :double-float)))
+ (t (ecase type
+ (:void :void)
+ (:integer :int)
+ (:character :char)
+ (:long :long)
+ (:single-float :float)
+ (:double-float :double)
+ (:string :string)
+ ;; Pass a pointer to the function.
+ (:callback :void)
+ (t (error 'unknown-token :token type
+ :message "Don't know the given Fortran type."))))))
+
+(defun %f77.get-return-type (type)
+ "
+ Return type understood by CFFI. Note that unlike arguments fortran
+ functions return-by-value."
+ (if (or (%f77.cast-as-array-p type) (%f77.callback-type-p type))
+ (error 'invalid-type :given type :expected '(not (or (%f77.cast-as-array-p type)
+ (%f77.callback-type-p type)))
+ :message "A Fortran function cannot return the given type.")
+ (%f77.cffi-type type)))
-;; If output
-(declaim (inline output-p))
-(defun output-p (style)
+(definline %f77.output-p (style)
+ "
+ Checks if style implies output."
(member style '(:output :input-output :workspace-output)))
-;; If input
-(declaim (inline input-p))
-(defun input-p (style)
- (member style '(:input :input-value :workspace)))
+(definline %f77.input-p (style)
+ "
+ Checks if style implies input."
+ (member style '(:input :input-value :input-reference :workspace)))
-;; CFFI doesn't nearly have as nice an FFI as SBCL/CMUCL.
-(defun get-read-in-type (type &optional (style :input))
- (unless (member style +ffi-styles+)
- (error "Don't know how to handle style ~A." style))
+(defun %f77.get-read-in-type (type &optional (style :input))
+ "
+ Get the input type to be passed to CFFI."
+ (assert (member style +ffi-styles+) nil 'unknown-token :token style
+ :message "Don't know how to handle style.")
(cond
;; Can't do much else if type is an array/complex or input is passed-by-value.
- ((or (callback-type-p type) (cast-as-array-p type) (eq style :input-value))
- (f77->cffi-type type))
+ ((or (%f77.callback-type-p type)
+ (%f77.cast-as-array-p type)
+ (eq style :input-value))
+ (%f77.cffi-type type))
;; else pass-by-reference
(t
- `(:pointer ,@(f77->cffi-type type)))))
-
-;; Separte the body of code into documentation and parameter lists.
-(defun parse-doc-&-parameters (body &optional header footer)
- (if (stringp (first body))
- (values `(,(%cat% header (first body) footer)) (rest body))
- (values (if (or header footer)
- (%cat% header "" footer)
- nil)
- body)))
-
-;; Parse fortran parameters and convert parameters to native C90 types (and
-;; add additional function parameters)
-(defun parse-fortran-parameters (body)
+ `(:pointer ,(%f77.cffi-type type)))))
+
+(defun %f77.parse-fortran-parameters (body)
+ "
+ Parse fortran parameters and convert parameters to native C90 types (and
+ add additional function parameters)."
(multiple-value-bind (doc pars)
(parse-doc-&-parameters body)
(declare (ignore doc))
@@ -111,200 +107,199 @@
(let* ((aux-pars nil)
(new-pars
(mapcar #'(lambda (decl)
- (destructuring-bind (name type &optional (style :input))
- decl
+ (destructuring-bind (name type &optional (style :input-reference)) decl
(case type
(:string
;; String lengths are appended to the function arguments,
;; passed by value.
- (nconsc aux-pars `((,(scat "LEN-" name) ,@(f77->cffi-type :integer))))
- `(,name ,@(f77->cffi-type :string)))
+ (nconsc aux-pars `((,(scat "LEN-" name) ,(%f77.cffi-type :integer))))
+ `(,name ,(%f77.cffi-type :string)))
(t
- `(,name ,@(get-read-in-type type style))))))
+ `(,name ,(%f77.get-read-in-type type style))))))
pars)))
`( ;; don't want documentation for direct interface, not useful
;; ,@doc
,@new-pars ,@aux-pars))))
-;;
-;; DEF-FORTRAN-ROUTINE
-;;
-;; An external Fortran routine definition form (DEF-FORTRAN-ROUTINE
-;; MY-FUN ...) creates two functions:
-;;
-;; 1. a raw FFI (foreign function interface),
-;; 2. an easier to use lisp interface to the raw interface.
-;;
-;; The documentation given here relates in the most part to the
-;; simplified lisp interface.
-;;
-;; Example:
-;; ========
-;; libblas.a contains the fortran subroutine DCOPY(N,X,INCX,Y,INCY)
-;; which copies the vector Y of N double-float's to the vector X.
-;; The function name in libblas.a is \"dcopy_\" (by Fortran convention).
-;;
-;; (DEF-FORTRAN-ROUTINE DCOPY :void
-;; (N :integer :input)
-;; (X (* :double-float) :output)
-;; (INCX :integer :input)
-;; (Y (* :double-float) :input)
-;; (INCY :integer :input))
-;;
-;; will expand into:
-;;
-;; (CFFI:DEFCFUN ("dcopy_" FORTRAN-DCOPY) :VOID
-;; (N :POINTER :INT)
-;; (DX :POINTER :DOUBLE)
-;; (INCX :POINTER :INT)
-;; (DY :POINTER :DOUBLE)
-;; (INCY :POINTER :INT))
-;;
-;; and
-;;
-;; (DEFUN DCOPY (N,X,INCX,Y,INCY)
-;; ...
-;;
-;; In turn, the lisp function DCOPY calls FORTRAN-DCOPY which calls
-;; the Fortran function "dcopy_" in libblas.a.
-;;
-;; Arguments:
-;; ==========
-;;
-;;
-;; NAME Name of the lisp interface function that will be created.
-;; The name of the raw FFI will be derived from NAME via
-;; the function MAKE-FFI-NAME. The name of foreign function
-;; (presumable a Fortran Function in an external library)
-;; will be derived from NAME via MAKE-FORTRAN-NAME.
-;;
-;; RETURN-TYPE
-;; The type of data that will be returned by the external
-;; (presumably Fortran) function.
-;;
-;; (MEMBER RETURN-TYPE '(:VOID :INTEGER :SINGLE-FLOAT :DOUBLE-FLOAT
-;; :COMPLEX-SINGLE-FLOAT :COMPLEX-DOUBLE-FLOAT))
-;;
-;; See GET-READ-OUT-TYPE.
-;;
-;; BODY A list of parameter forms. A parameter form is:
-;;
-;; (VARIABLE TYPE &optional (STYLE :INPUT))
-;;
-;; The VARIABLE is the name of a parameter accepted by the
-;; external (presumably Fortran) routine. TYPE is the type of
-;; VARIABLE. The recognized TYPE's are:
-;;
-;; TYPE Corresponds to Fortran Declaration
-;; ---- ----------------------------------
-;; :STRING CHARACTER*(*)
-;; :INTEGER INTEGER
-;; :SINGLE-FLOAT REAL
-;; :DOUBLE-FLOAT DOUBLE PRECISION
-;; :COMPLEX-SINGLE-FLOAT COMPLEX
-;; :COMPLEX-DOUBLE-FLOAT COMPLEX*16
-;; (* X) An array of type X.
-;; (:CALLBACK args) A description of a function or subroutine
-;;
-;; (MEMBER X '(:INTEGER :SINGLE-FLOAT :DOUBLE-FLOAT
-;; :COMPLEX-SINGLE-FLOAT :COMPLEX-DOUBLE-FLOAT)
-;;
-;;
-;; The STYLE (default :INPUT) defines how VARIABLE is treated.
-;; This is by far the most difficult quantity to learn. To
-;; begin with:
-;;
-;;
-;; (OR (MEMBER STYLE '(:INPUT :OUTPUT :INPUT-OUTPUT))
-;; (MEMBER STYLE '(:IN :COPY :IN-OUT :OUT)))
-;;
-;; TYPE STYLE Description
-;; ---- ----- -----------
-;; X :INPUT Value will be used but not modified.
-;;
-;; :OUTPUT Input value not used (but some value must be given),
-;; a value is returned as one of the values lisp
-;; function NAME. Similar to the :IN-OUT style
-;; of DEF-ALIEN-ROUTINE.
-;; :INPUT-OUTPUT Input value may be used, a value is returned
-;; as one of the values from the lisp function
-;; NAME.
-;;
-;; ** Note: In all 3 cases above the input VARIABLE will not be destroyed
-;; or modified directly, a copy is taken and a pointer of that
-;; copy is passed to the (presumably Fortran) external routine.
-;;
-;; (OR (* X) :INPUT Array entries are used but not modified.
-;; :STRING) :OUTPUT Array entries need not be initialized on input,
-;; but will be *modified*. In addition, the array
-;; will be returned via the Lisp command VALUES
-;; from the lisp function NAME.
-;;
-;; :INPUT-OUTPUT Like :OUTPUT but initial values on entry may be used.
-;;
-;; The keyword :WORKSPACE is a nickname for :INPUT. The
-;; keywords :INPUT-OR-OUTPUT, :WORKSPACE-OUTPUT,
-;; :WORKSPACE-OR-OUTPUT are nicknames for :OUTPUT.
-;;
-;; This is complicated. Suggestions are encouraged to
-;; interface a *functional language* to a *pass-by-reference
-;; language*.
-;;
-;; CALLBACKS
-;;
-;; A callback here means a function (or subroutine) that is passed into the Fortran
-;; routine which calls it as needed to compute something.
-;;
-;; The syntax of :CALLBACK is similar to the DEF-FORTRAN-ROUTINE:
-;;
-;; (name (:CALLBACK return-type
-;; {arg-description}))
-;;
-;; The RETURN-TYPE is the same as for DEF-FORTRAN-ROUTINE. The arg description is the
-;; same syntax as list of parameter forms for DEF-FORTRAN-ROUTINE. However, if the type
-;; is a pointer type (like (* :double-float)), then a required keyword option must be
-;; specified:
-;;
-;; (name (* type :size size) &optional style)
-;;
-;; The size specifies the total length of the Fortran array. This array is treated as a
-;; one dimentionsal vector and should be accessed using the function FV-REF, which is
-;; analogous to AREF. The SIZE parameter can be any Lisp form and can refer to any of the
-;; arguments to the Fortran routine.
-;;
-;; For example, a fortran routine can have the callback
-;;
-;; (def-fortran-routine foo :void
-;; (m (* :integer) :input)
-;; (fsub (:callback :void
-;; (x :double-float :input)
-;; (z (* :double-float :size (aref m 0)) :input)
-;; (f (* :double-float :size (aref m 0)) :output)))))
-;;
-;; This means that the arrays Z and F in FSUB have a dimension of (AREF M 0), the first
-;; element of the vector M. The function FSUB can be written in Lisp as
-;;
-;; (defun fsub (x z f)
-;; (setf (fv-ref f 0) (* x x (fv-ref z 3))))
-;;
-;; Further Notes:
-;; ===============
-;;
-;; Some Fortran routines use Fortran character strings in the
-;; parameter list. The definition here is suitable for Solaris
-;; where the Fortran character string is converted to a C-style null
-;; terminated string, AND an extra hidden parameter that is appended
-;; to the parameter list to hold the length of the string.
-;;
-;; If your Fortran does this differently, you'll have to change this
-;; definition accordingly!
-
-;; Call defcfun to define the foreign function.
-;; Also creates a nice lisp helper function.
-(defmacro def-fortran-routine (func-name return-type &rest body)
- (multiple-value-bind (fortran-name name) (if (listp func-name)
- (values (car func-name) (cadr func-name))
- (values (make-fortran-name func-name) func-name))
+(defmacro def-fortran-routine (name-and-options return-type &rest body)
+ "
+ DEF-FORTRAN-ROUTINE
+
+ An external Fortran routine definition form (DEF-FORTRAN-ROUTINE
+ MY-FUN ...) creates two functions:
+
+ 1. a raw FFI (foreign function interface),
+ 2. an easier to use lisp interface to the raw interface.
+
+ The documentation given here relates in the most part to the
+ simplified lisp interface.
+
+ Example:
+ ========
+ libblas.a contains the fortran subroutine DCOPY(N,X,INCX,Y,INCY)
+ which copies the vector Y of N double-float's to the vector X.
+ The function name in libblas.a is \"dcopy_\" (by Fortran convention).
+
+ (DEF-FORTRAN-ROUTINE DCOPY :void
+ (N :integer :input)
+ (X (* :double-float) :output)
+ (INCX :integer :input)
+ (Y (* :double-float) :input)
+ (INCY :integer :input))
+
+ will expand into:
+
+ (CFFI:DEFCFUN (\"dcopy_\" FORTRAN-DCOPY) :VOID
+ (N :POINTER :INT)
+ (DX :POINTER :DOUBLE)
+ (INCX :POINTER :INT)
+ (DY :POINTER :DOUBLE)
+ (INCY :POINTER :INT))
+
+ and
+
+ (DEFUN DCOPY (N,X,INCX,Y,INCY)
+ ...
+
+ In turn, the lisp function DCOPY calls FORTRAN-DCOPY which calls
+ the Fortran function \"dcopy_\" in libblas.a.
+
+ Arguments:
+ ==========
+
+
+ NAME Name of the lisp interface function that will be created.
+ The name of the raw FFI will be derived from NAME via
+ the function MAKE-FFI-NAME. The name of foreign function
+ (presumable a Fortran Function in an external library)
+ will be derived from NAME via MAKE-FORTRAN-NAME.
+
+ RETURN-TYPE
+ The type of data that will be returned by the external
+ (presumably Fortran) function.
+
+ (MEMBER RETURN-TYPE '(:VOID :INTEGER :SINGLE-FLOAT :DOUBLE-FLOAT
+ :COMPLEX-SINGLE-FLOAT :COMPLEX-DOUBLE-FLOAT))
+
+ See GET-READ-OUT-TYPE.
+
+ BODY A list of parameter forms. A parameter form is:
+
+ (VARIABLE TYPE &optional (STYLE :INPUT))
+
+ The VARIABLE is the name of a parameter accepted by the
+ external (presumably Fortran) routine. TYPE is the type of
+ VARIABLE. The recognized TYPE's are:
+
+ TYPE Corresponds to Fortran Declaration
+ ---- ----------------------------------
+ :STRING CHARACTER*(*)
+ :INTEGER INTEGER
+ :SINGLE-FLOAT REAL
+ :DOUBLE-FLOAT DOUBLE PRECISION
+ :COMPLEX-SINGLE-FLOAT COMPLEX
+ :COMPLEX-DOUBLE-FLOAT COMPLEX*16
+ (* X) An array of type X.
+ (:CALLBACK args) A description of a function or subroutine
+
+ (MEMBER X '(:INTEGER :SINGLE-FLOAT :DOUBLE-FLOAT
+ :COMPLEX-SINGLE-FLOAT :COMPLEX-DOUBLE-FLOAT)
+
+
+ The STYLE (default :INPUT) defines how VARIABLE is treated.
+ This is by far the most difficult quantity to learn. To
+ begin with:
+
+
+ (OR (MEMBER STYLE '(:INPUT :OUTPUT :INPUT-OUTPUT))
+ (MEMBER STYLE '(:IN :COPY :IN-OUT :OUT)))
+
+ TYPE STYLE Description
+ ---- ----- -----------
+ X :INPUT Value will be used but not modified.
+
+ :OUTPUT Input value not used (but some value must be given),
+ a value is returned as one of the values lisp
+ function NAME. Similar to the :IN-OUT style
+ of DEF-ALIEN-ROUTINE.
+ :INPUT-OUTPUT Input value may be used, a value is returned
+ as one of the values from the lisp function
+ NAME.
+
+ ** Note: In all 3 cases above the input VARIABLE will not be destroyed
+ or modified directly, a copy is taken and a pointer of that
+ copy is passed to the (presumably Fortran) external routine.
+
+ (OR (* X) :INPUT Array entries are used but not modified.
+ :STRING) :OUTPUT Array entries need not be initialized on input,
+ but will be *modified*. In addition, the array
+ will be returned via the Lisp command VALUES
+ from the lisp function NAME.
+
+ :INPUT-OUTPUT Like :OUTPUT but initial values on entry may be used.
+
+ The keyword :WORKSPACE is a nickname for :INPUT. The
+ keywords :INPUT-OR-OUTPUT, :WORKSPACE-OUTPUT,
+ :WORKSPACE-OR-OUTPUT are nicknames for :OUTPUT.
+
+ This is complicated. Suggestions are encouraged to
+ interface a *functional language* to a *pass-by-reference
+ language*.
+
+ CALLBACKS
+
+ A callback here means a function (or subroutine) that is passed into the Fortran
+ routine which calls it as needed to compute something.
+
+ The syntax of :CALLBACK is similar to the DEF-FORTRAN-ROUTINE:
+
+ (name (:CALLBACK return-type
+ {arg-description}))
+
+ The RETURN-TYPE is the same as for DEF-FORTRAN-ROUTINE. The arg description is the
+ same syntax as list of parameter forms for DEF-FORTRAN-ROUTINE. However, if the type
+ is a pointer type (like (* :double-float)), then a required keyword option must be
+ specified:
+
+ (name (* type :size size) &optional style)
+
+ The size specifies the total length of the Fortran array. This array is treated as a
+ one dimentionsal vector and should be accessed using the function FV-REF, which is
+ analogous to AREF. The SIZE parameter can be any Lisp form and can refer to any of the
+ arguments to the Fortran routine.
+
+ For example, a fortran routine can have the callback
+
+ (def-fortran-routine foo :void
+ (m (* :integer) :input)
+ (fsub (:callback :void
+ (x :double-float :input)
+ (z (* :double-float :size (aref m 0)) :input)
+ (f (* :double-float :size (aref m 0)) :output)))))
+
+ This means that the arrays Z and F in FSUB have a dimension of (AREF M 0), the first
+ element of the vector M. The function FSUB can be written in Lisp as
+
+ (defun fsub (x z f)
+ (setf (fv-ref f 0) (* x x (fv-ref z 3))))
+
+ Further Notes:
+ ===============
+
+ Some Fortran routines use Fortran character strings in the
+ parameter list. The definition here is suitable for Solaris
+ where the Fortran character string is converted to a C-style null
+ terminated string, AND an extra hidden parameter that is appended
+ to the parameter list to hold the length of the string.
+
+ If your Fortran does this differently, you'll have to change this
+ definition accordingly!
+
+ Call defcfun to define the foreign function.
+ Also creates a nice lisp helper function."
+ (multiple-value-bind (fortran-name name) (if (listp name-and-options)
+ (values (car name-and-options) (cadr name-and-options))
+ (values (make-fortran-name name-and-options) name-and-options))
(let* ((lisp-name (make-fortran-ffi-name `,name))
(hack-return-type `,return-type)
(hack-body `(,@body))
@@ -326,18 +321,13 @@
(setq hack-return-type :void)))
`(progn
- ;; Removing 'inlines' It seems that CMUCL has a problem with
- ;; inlines of FFI's when a lisp image is saved. Until the
- ;; matter is clarified we leave out 'inline's
-
- ;; (declaim (inline ,lisp-name)) ;sbcl 0.8.5 has problems with
- (cffi:defcfun (,fortran-name ,lisp-name) ,@(get-return-type hack-return-type)
- ,@(parse-fortran-parameters hack-body))
- ,@(def-fortran-interface name hack-return-type hack-body hidden-var-name)))))
+ (cffi:defcfun (,fortran-name ,lisp-name) ,(%f77.get-return-type hack-return-type)
+ ,@(%f77.parse-fortran-parameters hack-body))
+ ,@(%f77.def-fortran-interface name hack-return-type hack-body hidden-var-name)))))
;; Create a form specifying a simple Lisp function that calls the
;; underlying Fortran routine of the same name.
-(defun def-fortran-interface (name return-type body hidden-var-name)
+(defun %f77.def-fortran-interface (name return-type body hidden-var-name)
(multiple-value-bind (doc pars)
(parse-doc-&-parameters body)
(let ((ffi-fn (make-fortran-ffi-name name))
@@ -359,15 +349,15 @@
(aux-var nil))
(cond
;; Callbacks are tricky.
- ((callback-type-p type)
+ ((%f77.callback-type-p type)
(let* ((callback-name (gensym (symbol-name var)))
- (c-callback-code (def-fortran-callback var callback-name (second type) (cddr type))))
+ (c-callback-code (%f77.def-fortran-callback var callback-name (second type) (cddr type))))
(nconsc callback-code c-callback-code)
(setq ffi-var `(cffi:callback ,callback-name))))
;; Can't really enforce "style" when given an array.
;; Complex numbers do not latch onto this case, they
;; are passed by value.
- ((array-p type)
+ ((%f77.array-p type)
(setq ffi-var (scat "ADDR-" var))
(nconsc array-vars `((,ffi-var ,var)))
;;
@@ -376,7 +366,7 @@
`((,arg 0)))
(nconc (car (last array-vars)) `(:inc-type ,(cadr type) :inc ,arg))))
;; Strings
- ((string-p type)
+ ((%f77.string-p type)
(setq ffi-var var)
(setq aux-var (scat "LEN-" var))
(nconsc aux-args `((,aux-var (length (the string ,var))))))
@@ -392,13 +382,13 @@
((member type '(:complex-single-float :complex-double-float))
(setq ffi-var (scat "ADDR-REAL-CAST-" var))
(nconsc ref-vars
- `((,ffi-var ,(second (f77->cffi-type type)) :count 2 :initial-contents (list (realpart ,var) (imagpart ,var))))))
+ `((,ffi-var ,(second (%f77.cffi-type type)) :count 2 :initial-contents (list (realpart ,var) (imagpart ,var))))))
(t
(setq ffi-var (scat "REF-" var))
(nconsc ref-vars
- `((,ffi-var ,@(f77->cffi-type type) :initial-element ,var)))))))
+ `((,ffi-var ,(%f77.cffi-type type) :initial-element ,var)))))))
;; Output variables
- (when (and (output-p style) (not (eq type :string)))
+ (when (and (%f77.output-p style) (not (eq type :string)))
(nconsc return-vars
`((,ffi-var ,var ,type))))
;; Arguments for the lisp wrapper
@@ -448,9 +438,9 @@
,@(mapcar #'(lambda (decl)
(destructuring-bind (ffi-var var type) decl
(if (member type '(:complex-single-float :complex-double-float))
- `(setq ,var (complex (cffi:mem-aref ,ffi-var ,(second (f77->cffi-type type)) 0)
- (cffi:mem-aref ,ffi-var ,(second (f77->cffi-type type)) 1)))
- `(setq ,var (cffi:mem-aref ,ffi-var ,@(f77->cffi-type type))))))
+ `(setq ,var (complex (cffi:mem-aref ,ffi-var ,(second (%f77.cffi-type type)) 0)
+ (cffi:mem-aref ,ffi-var ,(second (%f77.cffi-type type)) 1)))
+ `(setq ,var (cffi:mem-aref ,ffi-var ,(%f77.cffi-type type))))))
(remove-if-not #'(lambda (x)
(member (first x) ref-vars :key #'car))
return-vars))
@@ -459,8 +449,133 @@
`(,retvar))
,@(mapcar #'second return-vars)))))))))
+#+nil
+(defun def-fortran-interface-func (name return-type body hidden-var-name)
+ (multiple-value-bind (doc pars)
+ (parse-doc-&-parameters body)
+ (let ((ffi-fn (make-fortran-ffi-name name))
+ (return-vars nil)
+ (array-vars nil)
+ (r...
[truncated message content] |