1 ! (c) 2009 Joe Groff, see BSD license
2 USING: accessors alien alien.complex alien.c-types alien.data
3 alien.parser grouping alien.strings alien.syntax arrays ascii
4 assocs byte-arrays combinators combinators.short-circuit fry
5 generalizations kernel lexer macros math math.parser namespaces
6 parser sequences sequences.generalizations splitting
7 stack-checker vectors vocabs.parser words locals
8 io.encodings.ascii io.encodings.string shuffle effects
9 math.ranges math.order sorting strings system alien.libraries ;
10 QUALIFIED-WITH: alien.c-types c
13 SINGLETONS: f2c-abi g95-abi gfortran-abi intel-unix-abi intel-windows-abi ;
15 TUPLE: bad-fortran-abi detail ;
16 C: <bad-fortran-abi> bad-fortran-abi
18 : alien>nstring ( alien len encoding -- string )
19 [ memory>byte-array ] dip decode ;
21 ERROR: invalid-fortran-type type ;
23 DEFER: fortran-sig>c-sig
24 DEFER: fortran-ret-type>c-type
25 DEFER: fortran-arg-type>c-type
26 DEFER: fortran-name>symbol-name
28 SYMBOL: library-fortran-abis
30 library-fortran-abis [ H{ } clone ] initialize
34 : lowercase-name-with-underscore ( name -- name' )
36 : lowercase-name-with-extra-underscore ( name -- name' )
37 >lower CHAR: _ over member?
38 [ "__" append ] [ "_" append ] if ;
40 HOOK: fortran-c-abi fortran-abi ( -- abi )
41 M: bad-fortran-abi fortran-c-abi cdecl ;
42 M: f2c-abi fortran-c-abi cdecl ;
43 M: g95-abi fortran-c-abi cdecl ;
44 M: gfortran-abi fortran-c-abi cdecl ;
45 M: intel-unix-abi fortran-c-abi cdecl ;
46 M: intel-windows-abi fortran-c-abi cdecl ;
48 HOOK: real-functions-return-double? fortran-abi ( -- ? )
49 M: f2c-abi real-functions-return-double? t ;
50 M: g95-abi real-functions-return-double? f ;
51 M: gfortran-abi real-functions-return-double? f ;
52 M: intel-unix-abi real-functions-return-double? f ;
53 M: intel-windows-abi real-functions-return-double? f ;
55 HOOK: complex-functions-return-by-value? fortran-abi ( -- ? )
56 M: f2c-abi complex-functions-return-by-value? f ;
57 M: g95-abi complex-functions-return-by-value? f ;
58 M: gfortran-abi complex-functions-return-by-value? t ;
59 M: intel-unix-abi complex-functions-return-by-value? f ;
60 M: intel-windows-abi complex-functions-return-by-value? f ;
62 HOOK: character(1)-maps-to-char? fortran-abi ( -- ? )
63 M: f2c-abi character(1)-maps-to-char? f ;
64 M: g95-abi character(1)-maps-to-char? f ;
65 M: gfortran-abi character(1)-maps-to-char? f ;
66 M: intel-unix-abi character(1)-maps-to-char? t ;
67 M: intel-windows-abi character(1)-maps-to-char? t ;
69 HOOK: mangle-name fortran-abi ( name -- name' )
70 M: f2c-abi mangle-name lowercase-name-with-extra-underscore ;
71 M: g95-abi mangle-name lowercase-name-with-extra-underscore ;
72 M: gfortran-abi mangle-name lowercase-name-with-underscore ;
73 M: intel-unix-abi mangle-name lowercase-name-with-underscore ;
74 M: intel-windows-abi mangle-name >upper ;
76 TUPLE: fortran-type dims size out? ;
78 TUPLE: number-type < fortran-type ;
79 TUPLE: integer-type < number-type ;
80 TUPLE: logical-type < integer-type ;
81 TUPLE: real-type < number-type ;
82 TUPLE: double-precision-type < number-type ;
84 TUPLE: character-type < fortran-type ;
85 TUPLE: misc-type < fortran-type name ;
87 TUPLE: complex-type < number-type ;
88 TUPLE: real-complex-type < complex-type ;
89 TUPLE: double-complex-type < complex-type ;
91 CONSTANT: fortran>c-types H{
92 { "character" character-type }
93 { "integer" integer-type }
94 { "logical" logical-type }
96 { "double-precision" double-precision-type }
97 { "complex" real-complex-type }
98 { "double-complex" double-complex-type }
101 : append-dimensions ( base-c-type type -- c-type )
102 dims>> [ product 2array ] when* ;
104 MACRO: size-case-type ( cases -- quot )
105 [ throw-invalid-fortran-type ] suffix
106 '[ [ size>> _ case ] [ append-dimensions ] bi ] ;
108 : simple-type ( type base-c-type -- c-type )
110 [ dup size>> [ throw-invalid-fortran-type ] [ drop ] if ]
111 [ append-dimensions ] bi ;
113 : new-fortran-type ( out? dims size class -- type )
114 new [ [ size<< ] [ dims<< ] [ out?<< ] tri ] keep ;
116 GENERIC: (fortran-type>c-type) ( type -- c-type )
118 M: f (fortran-type>c-type) drop c:void ;
120 M: integer-type (fortran-type>c-type)
128 M: real-type (fortran-type>c-type)
134 M: real-complex-type (fortran-type>c-type)
136 { f [ complex-float ] }
137 { 8 [ complex-float ] }
138 { 16 [ complex-double ] }
141 M: double-precision-type (fortran-type>c-type)
142 c:double simple-type ;
143 M: double-complex-type (fortran-type>c-type)
144 complex-double simple-type ;
145 M: misc-type (fortran-type>c-type)
146 dup name>> parse-c-type simple-type ;
148 : single-char? ( character-type -- ? )
149 { [ drop character(1)-maps-to-char? ] [ dims>> product 1 = ] } 1&& ;
151 : fix-character-type ( character-type -- character-type' )
153 [ dup dims>> [ throw-invalid-fortran-type ] [ dup size>> 1array >>dims f >>size ] if ]
154 [ dup dims>> [ ] [ f >>dims ] if ] if
155 dup single-char? [ f >>dims ] when ;
157 M: character-type (fortran-type>c-type)
158 fix-character-type c:char simple-type ;
160 : dimension>number ( string -- number )
161 dup "*" = [ drop 0 ] [ string>number ] if ;
163 : parse-out ( string -- string' out? )
166 : parse-dims ( string -- string' dim )
168 [ ")" ?tail drop "," split [ [ blank? ] trim dimension>number ] map ] when ;
170 : parse-size ( string -- string' size )
171 "*" split1 dup [ string>number ] when ;
173 : (parse-fortran-type) ( fortran-type-string -- type )
174 parse-out swap parse-dims swap parse-size swap
175 >lower fortran>c-types ?at
176 [ new-fortran-type ] [ misc-type boa ] if ;
178 : parse-fortran-type ( fortran-type-string/f -- type/f )
179 dup [ (parse-fortran-type) ] when ;
181 GENERIC: added-c-args ( type -- args )
183 M: fortran-type added-c-args drop { } ;
184 M: character-type added-c-args fix-character-type single-char? [ { } ] [ { c:long } ] if ;
186 GENERIC: returns-by-value? ( type -- ? )
188 M: f returns-by-value? drop t ;
189 M: fortran-type returns-by-value? drop f ;
190 M: number-type returns-by-value? dims>> not ;
191 M: character-type returns-by-value? fix-character-type single-char? ;
192 M: complex-type returns-by-value?
193 { [ drop complex-functions-return-by-value? ] [ dims>> not ] } 1&& ;
195 GENERIC: (fortran-ret-type>c-type) ( type -- c-type )
197 M: f (fortran-ret-type>c-type) drop c:void ;
198 M: fortran-type (fortran-ret-type>c-type) (fortran-type>c-type) ;
199 M: real-type (fortran-ret-type>c-type)
200 drop real-functions-return-double? [ c:double ] [ c:float ] if ;
202 GENERIC: (fortran-arg>c-args) ( type -- main-quot added-quot )
204 : args?dims ( type quot -- main-quot added-quot )
205 [ dup dims>> [ drop [ ] [ drop ] ] ] dip if ; inline
207 M: integer-type (fortran-arg>c-args)
210 { f [ [ c:int <ref> ] [ drop ] ] }
211 { 1 [ [ c:char <ref> ] [ drop ] ] }
212 { 2 [ [ c:short <ref> ] [ drop ] ] }
213 { 4 [ [ c:int <ref> ] [ drop ] ] }
214 { 8 [ [ c:longlong <ref> ] [ drop ] ] }
215 [ throw-invalid-fortran-type ]
219 M: logical-type (fortran-arg>c-args)
220 [ call-next-method [ [ 1 0 ? ] prepend ] dip ] args?dims ;
222 M: real-type (fortran-arg>c-args)
225 { f [ [ c:float <ref> ] [ drop ] ] }
226 { 4 [ [ c:float <ref> ] [ drop ] ] }
227 { 8 [ [ c:double <ref> ] [ drop ] ] }
228 [ throw-invalid-fortran-type ]
232 M: real-complex-type (fortran-arg>c-args)
235 { f [ [ <complex-float> ] [ drop ] ] }
236 { 8 [ [ <complex-float> ] [ drop ] ] }
237 { 16 [ [ <complex-double> ] [ drop ] ] }
238 [ throw-invalid-fortran-type ]
242 M: double-precision-type (fortran-arg>c-args)
243 [ drop [ c:double <ref> ] [ drop ] ] args?dims ;
245 M: double-complex-type (fortran-arg>c-args)
246 [ drop [ <complex-double> ] [ drop ] ] args?dims ;
248 M: character-type (fortran-arg>c-args)
249 fix-character-type single-char?
250 [ [ first c:char <ref> ] [ drop ] ]
251 [ [ ascii string>alien ] [ length ] ] if ;
253 M: misc-type (fortran-arg>c-args)
256 GENERIC: (fortran-result>) ( type -- quots )
258 : result?dims ( type quot -- quot )
259 [ dup dims>> [ drop { [ ] } ] ] dip if ; inline
261 M: integer-type (fortran-result>)
264 { f [ { [ c:int deref ] } ] }
265 { 1 [ { [ c:char deref ] } ] }
266 { 2 [ { [ c:short deref ] } ] }
267 { 4 [ { [ c:int deref ] } ] }
268 { 8 [ { [ c:longlong deref ] } ] }
269 [ throw-invalid-fortran-type ]
273 M: logical-type (fortran-result>)
274 [ call-next-method first [ zero? not ] append 1array ] result?dims ;
276 M: real-type (fortran-result>)
278 { f [ { [ c:float deref ] } ] }
279 { 4 [ { [ c:float deref ] } ] }
280 { 8 [ { [ c:double deref ] } ] }
281 [ throw-invalid-fortran-type ]
282 } case ] result?dims ;
284 M: real-complex-type (fortran-result>)
286 { f [ { [ *complex-float ] } ] }
287 { 8 [ { [ *complex-float ] } ] }
288 { 16 [ { [ *complex-double ] } ] }
289 [ throw-invalid-fortran-type ]
290 } case ] result?dims ;
292 M: double-precision-type (fortran-result>)
293 [ drop { [ c:double deref ] } ] result?dims ;
295 M: double-complex-type (fortran-result>)
296 [ drop { [ *complex-double ] } ] result?dims ;
298 M: character-type (fortran-result>)
299 fix-character-type single-char?
300 [ { [ c:char deref 1string ] } ]
301 [ { [ ] [ ascii alien>nstring ] } ] if ;
303 M: misc-type (fortran-result>)
306 GENERIC: (<fortran-result>) ( type -- quot )
308 M: fortran-type (<fortran-result>)
309 (fortran-type>c-type) \ heap-size \ <byte-array> [ ] 3sequence ;
311 M: character-type (<fortran-result>)
312 fix-character-type dims>> product dup
313 [ \ <byte-array> ] dip [ ] 3sequence ;
315 : [<fortran-result>] ( return parameters -- quot )
316 [ parse-fortran-type ] dip
317 over returns-by-value?
319 [ [ (<fortran-result>) ] [ length \ ndip [ ] 3sequence ] bi* ] if ;
321 : [fortran-args>c-args] ( parameters -- quot )
323 [ parse-fortran-type (fortran-arg>c-args) 2array ] map flip first2
324 [ [ \ spread [ ] 2sequence ] bi@ 2array ] [ length ] bi
325 \ ncleave [ ] 3sequence
328 :: [fortran-invoke] ( [args>args] return library function parameters -- [args>args] quot )
329 return parameters fortran-sig>c-sig :> ( c-return c-parameters )
330 function fortran-name>symbol-name :> c-function
332 c-return library c-function c-parameters \ alien-invoke
334 c-parameters length \ nkeep
337 : [fortran-out-param>] ( parameter -- quot )
339 [ (fortran-result>) ] [ out?>> ] bi
340 [ ] [ [ drop [ drop ] ] map ] if ;
342 : [fortran-return>] ( return -- quot )
344 { [ dup not ] [ drop { } ] }
345 { [ dup returns-by-value? ] [ drop { [ ] } ] }
346 [ (fortran-result>) ]
349 : letters ( -- seq ) CHAR: a CHAR: z [a,b] ;
351 : (shuffle-map) ( return parameters -- ret par )
353 fortran-ret-type>c-type length swap void? [ 1 + ] unless
354 letters swap head [ "ret" swap suffix ] map
356 [ fortran-arg-type>c-type nip length 1 + ] map letters swap zip
357 [ first2 letters swap head [ "" 2sequence ] with map ] map concat
360 : (fortran-in-shuffle) ( ret par -- seq )
361 [ second ] sort-with append ;
363 : (fortran-out-shuffle) ( ret par -- seq )
366 : [fortran-result-shuffle] ( return parameters -- quot )
367 (shuffle-map) [ (fortran-in-shuffle) ] [ (fortran-out-shuffle) ] 2bi <effect>
368 \ shuffle-effect [ ] 2sequence ;
370 : [fortran-results>] ( return parameters -- quot )
371 [ [fortran-result-shuffle] ]
372 [ drop [fortran-return>] ]
373 [ nip [ [fortran-out-param>] ] map concat ] 2tri
375 \ spread [ ] 2sequence append ;
377 : (add-fortran-library) ( fortran-abi name -- )
378 library-fortran-abis get-global set-at ;
382 : add-fortran-library ( name soname fortran-abi -- )
383 [ fortran-abi [ fortran-c-abi ] with-variable add-library ]
384 [ nip swap (add-fortran-library) ] 3bi ;
386 : fortran-name>symbol-name ( fortran-name -- c-name )
389 : fortran-type>c-type ( fortran-type -- c-type )
390 parse-fortran-type (fortran-type>c-type) ;
392 : fortran-arg-type>c-type ( fortran-type -- c-type added-args )
394 [ (fortran-type>c-type) <pointer> ]
395 [ added-c-args ] bi ;
396 : fortran-ret-type>c-type ( fortran-type -- c-type added-args )
397 parse-fortran-type dup returns-by-value?
398 [ (fortran-ret-type>c-type) { } ] [
400 [ added-c-args ] [ (fortran-type>c-type) <pointer> ] bi prefix
403 : fortran-arg-types>c-types ( fortran-types -- c-types )
404 [ length <vector> 1 <vector> ] keep
405 [ fortran-arg-type>c-type swapd [ suffix! ] [ append! ] 2bi* ] each
408 : fortran-sig>c-sig ( fortran-return fortran-args -- c-return c-args )
409 [ fortran-ret-type>c-type ] [ fortran-arg-types>c-types ] bi* append ;
411 : set-fortran-abi ( library -- )
412 library-fortran-abis get-global at fortran-abi set ;
414 : ((fortran-invoke)) ( return library function parameters -- quot )
416 [ 2nip [<fortran-result>] ]
417 [ nip nip nip [fortran-args>c-args] ]
419 [ 2nip [fortran-results>] ]
420 } 4 ncleave 4 nappend ;
422 :: (fortran-invoke) ( return library function parameters -- quot )
423 library library-fortran-abis get-global at dup bad-fortran-abi?
425 [ drop return library function parameters ((fortran-invoke)) ] if ;
427 MACRO: fortran-invoke ( return library function parameters -- quot )
428 { [ 2drop nip set-fortran-abi ] [ (fortran-invoke) ] } 4 ncleave ;
430 : parse-arglist ( parameters return -- types effect )
433 [ unzip [ "," ?tail drop ] map ]
434 [ [ first "!" head? ] filter [ second "," ?tail drop "'" append ] map ] bi
435 ] [ [ ] [ prefix ] if-void ]
438 :: define-fortran-function ( return library function parameters -- )
439 function create-function
440 return library function parameters return [ c:void ] unless* parse-arglist
441 [ \ fortran-invoke 5 [ ] nsequence ] dip define-declared ;
444 f current-library get scan-token ")" parse-tokens
445 [ "()" subseq? ] reject define-fortran-function ;
448 scan-token current-library get scan-token ")" parse-tokens
449 [ "()" subseq? ] reject define-fortran-function ;
453 [ current-library set ]
454 [ set-fortran-abi ] bi ;