]> gitweb.factorcode.org Git - factor.git/blob - basis/alien/fortran/fortran.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / basis / alien / fortran / fortran.factor
1 ! (c) 2009 Joe Groff, see BSD license
2 USING: accessors alien alien.c-types alien.complex alien.parser
3 alien.strings alien.structs alien.syntax arrays ascii assocs
4 byte-arrays combinators combinators.short-circuit fry generalizations
5 kernel lexer macros math math.parser namespaces parser sequences
6 splitting stack-checker vectors vocabs.parser words locals
7 io.encodings.ascii io.encodings.string shuffle effects math.ranges
8 math.order sorting strings system ;
9 IN: alien.fortran
10
11 SINGLETONS: f2c-abi gfortran-abi intel-unix-abi intel-windows-abi ;
12
13 << 
14 : add-f2c-libraries ( -- )
15     "I77" "libI77.so" "cdecl" add-library
16     "F77" "libF77.so" "cdecl" add-library ;
17
18 os netbsd? [ add-f2c-libraries ] when
19 >>
20
21 : alien>nstring ( alien len encoding -- string )
22     [ memory>byte-array ] dip decode ;
23
24 ERROR: invalid-fortran-type type ;
25
26 DEFER: fortran-sig>c-sig
27 DEFER: fortran-ret-type>c-type
28 DEFER: fortran-arg-type>c-type
29 DEFER: fortran-name>symbol-name
30
31 SYMBOL: library-fortran-abis
32 SYMBOL: fortran-abi
33 library-fortran-abis [ H{ } clone ] initialize
34
35 <PRIVATE
36
37 : lowercase-name-with-underscore ( name -- name' )
38     >lower "_" append ;
39 : lowercase-name-with-extra-underscore ( name -- name' )
40     >lower CHAR: _ over member? 
41     [ "__" append ] [ "_" append ] if ;
42
43 HOOK: fortran-c-abi fortran-abi ( -- abi )
44 M: f2c-abi fortran-c-abi "cdecl" ;
45 M: gfortran-abi fortran-c-abi "cdecl" ;
46 M: intel-unix-abi fortran-c-abi "cdecl" ;
47 M: intel-windows-abi fortran-c-abi "cdecl" ;
48
49 HOOK: real-functions-return-double? fortran-abi ( -- ? )
50 M: f2c-abi real-functions-return-double? t ;
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 ;
54
55 HOOK: complex-functions-return-by-value? fortran-abi ( -- ? )
56 M: f2c-abi complex-functions-return-by-value? f ;
57 M: gfortran-abi complex-functions-return-by-value? t ;
58 M: intel-unix-abi complex-functions-return-by-value? f ;
59 M: intel-windows-abi complex-functions-return-by-value? f ;
60
61 HOOK: character(1)-maps-to-char? fortran-abi ( -- ? )
62 M: f2c-abi character(1)-maps-to-char? f ;
63 M: gfortran-abi character(1)-maps-to-char? f ;
64 M: intel-unix-abi character(1)-maps-to-char? t ;
65 M: intel-windows-abi character(1)-maps-to-char? t ;
66
67 HOOK: mangle-name fortran-abi ( name -- name' )
68 M: f2c-abi mangle-name lowercase-name-with-extra-underscore ;
69 M: gfortran-abi mangle-name lowercase-name-with-underscore ;
70 M: intel-unix-abi mangle-name lowercase-name-with-underscore ;
71 M: intel-windows-abi mangle-name >upper ;
72
73 TUPLE: fortran-type dims size out? ;
74
75 TUPLE: number-type < fortran-type ;
76 TUPLE: integer-type < number-type ;
77 TUPLE: logical-type < integer-type ;
78 TUPLE: real-type < number-type ;
79 TUPLE: double-precision-type < number-type ;
80
81 TUPLE: character-type < fortran-type ;
82 TUPLE: misc-type < fortran-type name ;
83
84 TUPLE: complex-type < number-type ;
85 TUPLE: real-complex-type < complex-type ;
86 TUPLE: double-complex-type < complex-type ;
87
88 CONSTANT: fortran>c-types H{
89     { "character"        character-type        }
90     { "integer"          integer-type          }
91     { "logical"          logical-type          }
92     { "real"             real-type             }
93     { "double-precision" double-precision-type }
94     { "complex"          real-complex-type     }
95     { "double-complex"   double-complex-type   }
96 }
97
98 : append-dimensions ( base-c-type type -- c-type )
99     dims>>
100     [ product number>string "[" "]" surround append ] when* ;
101
102 MACRO: size-case-type ( cases -- )
103     [ invalid-fortran-type ] suffix
104     '[ [ size>> _ case ] [ append-dimensions ] bi ] ;
105
106 : simple-type ( type base-c-type -- c-type )
107     swap
108     [ dup size>> [ invalid-fortran-type ] [ drop ] if ]
109     [ append-dimensions ] bi ;
110
111 : new-fortran-type ( out? dims size class -- type )
112     new [ [ (>>size) ] [ (>>dims) ] [ (>>out?) ] tri ] keep ;
113
114 GENERIC: (fortran-type>c-type) ( type -- c-type )
115
116 M: f (fortran-type>c-type) drop "void" ;
117
118 M: integer-type (fortran-type>c-type)
119     {
120         { f [ "int"      ] }
121         { 1 [ "char"     ] }
122         { 2 [ "short"    ] }
123         { 4 [ "int"      ] }
124         { 8 [ "longlong" ] }
125     } size-case-type ;
126 M: real-type (fortran-type>c-type)
127     {
128         { f [ "float"  ] }
129         { 4 [ "float"  ] }
130         { 8 [ "double" ] }
131     } size-case-type ;
132 M: real-complex-type (fortran-type>c-type)
133     {
134         {  f [ "complex-float"  ] }
135         {  8 [ "complex-float"  ] }
136         { 16 [ "complex-double" ] }
137     } size-case-type ;
138
139 M: double-precision-type (fortran-type>c-type)
140     "double" simple-type ;
141 M: double-complex-type (fortran-type>c-type)
142     "complex-double" simple-type ;
143 M: misc-type (fortran-type>c-type)
144     dup name>> simple-type ;
145
146 : single-char? ( character-type -- ? )
147     { [ drop character(1)-maps-to-char? ] [ dims>> product 1 = ] } 1&& ;
148
149 : fix-character-type ( character-type -- character-type' )
150     clone dup size>>
151     [ dup dims>> [ invalid-fortran-type ] [ dup size>> 1array >>dims f >>size ] if ]
152     [ dup dims>> [ ] [ f >>dims ] if ] if
153     dup single-char? [ f >>dims ] when ;
154
155 M: character-type (fortran-type>c-type)
156     fix-character-type "char" simple-type ;
157
158 : dimension>number ( string -- number )
159     dup "*" = [ drop 0 ] [ string>number ] if ;
160
161 : parse-out ( string -- string' out? )
162     "!" ?head ;
163
164 : parse-dims ( string -- string' dim )
165     "(" split1 dup
166     [ ")" ?tail drop "," split [ [ blank? ] trim dimension>number ] map ] when ;
167
168 : parse-size ( string -- string' size )
169     "*" split1 dup [ string>number ] when ;
170
171 : (parse-fortran-type) ( fortran-type-string -- type )
172     parse-out swap parse-dims swap parse-size swap
173     >lower fortran>c-types ?at
174     [ new-fortran-type ] [ misc-type boa ] if ;
175
176 : parse-fortran-type ( fortran-type-string/f -- type/f )
177     dup [ (parse-fortran-type) ] when ;
178
179 : c-type>pointer ( c-type -- c-type* )
180     "[" split1 drop "*" append ;
181
182 GENERIC: added-c-args ( type -- args )
183
184 M: fortran-type added-c-args drop { } ;
185 M: character-type added-c-args fix-character-type single-char? [ { } ] [ { "long" } ] if ;
186
187 GENERIC: returns-by-value? ( type -- ? )
188
189 M: f returns-by-value? drop t ;
190 M: fortran-type returns-by-value? drop f ;
191 M: number-type returns-by-value? dims>> not ;
192 M: character-type returns-by-value? fix-character-type single-char? ;
193 M: complex-type returns-by-value?
194     { [ drop complex-functions-return-by-value? ] [ dims>> not ] } 1&& ;
195
196 GENERIC: (fortran-ret-type>c-type) ( type -- c-type )
197
198 M: f (fortran-ret-type>c-type) drop "void" ;
199 M: fortran-type (fortran-ret-type>c-type) (fortran-type>c-type) ;
200 M: real-type (fortran-ret-type>c-type)
201     drop real-functions-return-double? [ "double" ] [ "float" ] if ;
202
203 : suffix! ( seq   elt   -- seq   ) over push     ; inline
204 : append! ( seq-a seq-b -- seq-a ) over push-all ; inline
205
206 GENERIC: (fortran-arg>c-args) ( type -- main-quot added-quot )
207
208 : args?dims ( type quot -- main-quot added-quot )
209     [ dup dims>> [ drop [ ] [ drop ] ] ] dip if ; inline
210
211 M: integer-type (fortran-arg>c-args)
212     [
213         size>> {
214             { f [ [ <int>      ] [ drop ] ] }
215             { 1 [ [ <char>     ] [ drop ] ] }
216             { 2 [ [ <short>    ] [ drop ] ] }
217             { 4 [ [ <int>      ] [ drop ] ] }
218             { 8 [ [ <longlong> ] [ drop ] ] }
219             [ invalid-fortran-type ]
220         } case
221     ] args?dims ;
222
223 M: logical-type (fortran-arg>c-args)
224     [ call-next-method [ [ 1 0 ? ] prepend ] dip ] args?dims ;
225
226 M: real-type (fortran-arg>c-args)
227     [
228         size>> {
229             { f [ [ <float>  ] [ drop ] ] }
230             { 4 [ [ <float>  ] [ drop ] ] }
231             { 8 [ [ <double> ] [ drop ] ] }
232             [ invalid-fortran-type ]
233         } case
234     ] args?dims ;
235
236 M: real-complex-type (fortran-arg>c-args)
237     [
238         size>> {
239             {  f [ [ <complex-float>  ] [ drop ] ] }
240             {  8 [ [ <complex-float>  ] [ drop ] ] }
241             { 16 [ [ <complex-double> ] [ drop ] ] }
242             [ invalid-fortran-type ]
243         } case
244     ] args?dims ;
245
246 M: double-precision-type (fortran-arg>c-args)
247     [ drop [ <double> ] [ drop ] ] args?dims ;
248
249 M: double-complex-type (fortran-arg>c-args)
250     [ drop [ <complex-double> ] [ drop ] ] args?dims ;
251
252 M: character-type (fortran-arg>c-args)
253     fix-character-type single-char?
254     [ [ first <char> ] [ drop ] ]
255     [ [ ascii string>alien ] [ length ] ] if ;
256
257 M: misc-type (fortran-arg>c-args)
258     drop [ ] [ drop ] ;
259
260 GENERIC: (fortran-result>) ( type -- quots )
261
262 : result?dims ( type quot -- quot )
263     [ dup dims>> [ drop { [ ] } ] ] dip if ; inline
264
265 M: integer-type (fortran-result>)
266     [ size>> {
267         { f [ { [ *int      ] } ] }
268         { 1 [ { [ *char     ] } ] }
269         { 2 [ { [ *short    ] } ] }
270         { 4 [ { [ *int      ] } ] }
271         { 8 [ { [ *longlong ] } ] }
272         [ invalid-fortran-type ]
273     } case ] result?dims ;
274
275 M: logical-type (fortran-result>)
276     [ call-next-method first [ zero? not ] append 1array ] result?dims ;
277
278 M: real-type (fortran-result>)
279     [ size>> {
280         { f [ { [ *float  ] } ] }
281         { 4 [ { [ *float  ] } ] }
282         { 8 [ { [ *double ] } ] }
283         [ invalid-fortran-type ]
284     } case ] result?dims ;
285
286 M: real-complex-type (fortran-result>)
287     [ size>> {
288         {  f [ { [ *complex-float  ] } ] }
289         {  8 [ { [ *complex-float  ] } ] }
290         { 16 [ { [ *complex-double ] } ] }
291         [ invalid-fortran-type ]
292     } case ] result?dims ;
293
294 M: double-precision-type (fortran-result>)
295     [ drop { [ *double ] } ] result?dims ;
296
297 M: double-complex-type (fortran-result>)
298     [ drop { [ *complex-double ] } ] result?dims ;
299
300 M: character-type (fortran-result>)
301     fix-character-type single-char?
302     [ { [ *char 1string ] } ]
303     [ { [ ] [ ascii alien>nstring ] } ] if ;
304
305 M: misc-type (fortran-result>)
306     drop { [ ] } ;
307
308 GENERIC: (<fortran-result>) ( type -- quot )
309
310 M: fortran-type (<fortran-result>) 
311     (fortran-type>c-type) \ <c-object> [ ] 2sequence ;
312
313 M: character-type (<fortran-result>)
314     fix-character-type dims>> product dup
315     [ \ <byte-array> ] dip [ ] 3sequence ;
316
317 : [<fortran-result>] ( return parameters -- quot )
318     [ parse-fortran-type ] dip
319     over returns-by-value?
320     [ 2drop [ ] ]
321     [ [ (<fortran-result>) ] [ length \ ndip [ ] 3sequence ] bi* ] if ;
322
323 : [fortran-args>c-args] ( parameters -- quot )
324     [ [ ] ] [
325         [ parse-fortran-type (fortran-arg>c-args) 2array ] map flip first2
326         [ [ \ spread [ ] 2sequence ] bi@ 2array ] [ length ] bi 
327         \ ncleave [ ] 3sequence
328     ] if-empty ;
329
330 :: [fortran-invoke] ( [args>args] return library function parameters -- [args>args] quot ) 
331     return parameters fortran-sig>c-sig :> c-parameters :> c-return
332     function fortran-name>symbol-name :> c-function
333     [args>args] 
334     c-return library c-function c-parameters \ alien-invoke
335     5 [ ] nsequence
336     c-parameters length \ nkeep
337     [ ] 3sequence ;
338
339 : [fortran-out-param>] ( parameter -- quot )
340     parse-fortran-type
341     [ (fortran-result>) ] [ out?>> ] bi
342     [ ] [ [ drop [ drop ] ] map ] if ;
343
344 : [fortran-return>] ( return -- quot )
345     parse-fortran-type {
346         { [ dup not ] [ drop { } ] }
347         { [ dup returns-by-value? ] [ drop { [ ] } ] }
348         [ (fortran-result>) ]
349     } cond ;
350
351 : letters ( -- seq ) CHAR: a CHAR: z [a,b] ;
352
353 : (shuffle-map) ( return parameters -- ret par )
354     [
355         fortran-ret-type>c-type length swap "void" = [ 1+ ] unless
356         letters swap head [ "ret" swap suffix ] map
357     ] [
358         [ fortran-arg-type>c-type nip length 1+ ] map letters swap zip
359         [ first2 letters swap head [ "" 2sequence ] with map ] map concat
360     ] bi* ;
361
362 : (fortran-in-shuffle) ( ret par -- seq )
363     [ [ second ] bi@ <=> ] sort append ;
364
365 : (fortran-out-shuffle) ( ret par -- seq )
366     append ;
367
368 : [fortran-result-shuffle] ( return parameters -- quot )
369     (shuffle-map) [ (fortran-in-shuffle) ] [ (fortran-out-shuffle) ] 2bi <effect>
370     \ shuffle-effect [ ] 2sequence ;
371
372 : [fortran-results>] ( return parameters -- quot )
373     [ [fortran-result-shuffle] ]
374     [ drop [fortran-return>] ]
375     [ nip [ [fortran-out-param>] ] map concat ] 2tri
376     append
377     \ spread [ ] 2sequence append ;
378
379 : (add-fortran-library) ( fortran-abi name -- )
380     library-fortran-abis get-global set-at ;
381
382 PRIVATE>
383
384 : add-fortran-library ( name soname fortran-abi -- )
385     [ fortran-abi [ fortran-c-abi ] with-variable add-library ]
386     [ nip swap (add-fortran-library) ] 3bi ;
387
388 : fortran-name>symbol-name ( fortran-name -- c-name )
389     mangle-name ;
390
391 : fortran-type>c-type ( fortran-type -- c-type )
392     parse-fortran-type (fortran-type>c-type) ;
393
394 : fortran-arg-type>c-type ( fortran-type -- c-type added-args )
395     parse-fortran-type
396     [ (fortran-type>c-type) c-type>pointer ]
397     [ added-c-args ] bi ;
398 : fortran-ret-type>c-type ( fortran-type -- c-type added-args )
399     parse-fortran-type dup returns-by-value?
400     [ (fortran-ret-type>c-type) { } ] [
401         "void" swap 
402         [ added-c-args ] [ (fortran-type>c-type) c-type>pointer ] bi prefix
403     ] if ;
404
405 : fortran-arg-types>c-types ( fortran-types -- c-types )
406     [ length <vector> 1 <vector> ] keep
407     [ fortran-arg-type>c-type swapd [ suffix! ] [ append! ] 2bi* ] each
408     append >array ;
409
410 : fortran-sig>c-sig ( fortran-return fortran-args -- c-return c-args )
411     [ fortran-ret-type>c-type ] [ fortran-arg-types>c-types ] bi* append ;
412
413 : fortran-record>c-struct ( record -- struct )
414     [ first2 [ fortran-type>c-type ] [ >lower ] bi* 2array ] map ;
415
416 : define-fortran-record ( name vocab fields -- )
417     [ >lower ] [ ] [ fortran-record>c-struct ] tri* define-struct ;
418
419 SYNTAX: RECORD: scan in get parse-definition define-fortran-record ;
420
421 : set-fortran-abi ( library -- )
422     library-fortran-abis get-global at fortran-abi set ;
423
424 : (fortran-invoke) ( return library function parameters -- quot )
425     {
426         [ 2nip [<fortran-result>] ]
427         [ nip nip nip [fortran-args>c-args] ]
428         [ [fortran-invoke] ]
429         [ 2nip [fortran-results>] ]
430     } 4 ncleave 4 nappend ;
431
432 MACRO: fortran-invoke ( return library function parameters -- )
433     { [ 2drop nip set-fortran-abi ] [ (fortran-invoke) ] } 4 ncleave ;
434
435 :: define-fortran-function ( return library function parameters -- )
436     function create-in dup reset-generic 
437     return library function parameters return [ "void" ] unless* parse-arglist
438     [ \ fortran-invoke 5 [ ] nsequence ] dip define-declared ;
439
440 SYNTAX: SUBROUTINE: 
441     f "c-library" get scan ";" parse-tokens
442     [ "()" subseq? not ] filter define-fortran-function ;
443
444 SYNTAX: FUNCTION:
445     scan "c-library" get scan ";" parse-tokens
446     [ "()" subseq? not ] filter define-fortran-function ;
447
448 SYNTAX: LIBRARY:
449     scan
450     [ "c-library" set ]
451     [ set-fortran-abi ] bi ;
452