]> gitweb.factorcode.org Git - factor.git/blob - extra/alien/fortran/fortran.factor
factor: Fix rename issues.
[factor.git] / extra / alien / fortran / fortran.factor
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
11 IN: alien.fortran
12
13 SINGLETONS: f2c-abi g95-abi gfortran-abi intel-unix-abi intel-windows-abi ;
14
15 TUPLE: bad-fortran-abi detail ;
16 C: <bad-fortran-abi> bad-fortran-abi
17
18 : alien>nstring ( alien len encoding -- string )
19     [ memory>byte-array ] dip decode ;
20
21 ERROR: invalid-fortran-type type ;
22
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
27
28 SYMBOL: library-fortran-abis
29 SYMBOL: fortran-abi
30 library-fortran-abis [ H{ } clone ] initialize
31
32 <PRIVATE
33
34 : lowercase-name-with-underscore ( name -- name' )
35     >lower "_" append ;
36 : lowercase-name-with-extra-underscore ( name -- name' )
37     >lower CHAR: _ over member?
38     [ "__" append ] [ "_" append ] if ;
39
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 ;
47
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 ;
54
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 ;
61
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 ;
68
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 ;
75
76 TUPLE: fortran-type dims size out? ;
77
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 ;
83
84 TUPLE: character-type < fortran-type ;
85 TUPLE: misc-type < fortran-type name ;
86
87 TUPLE: complex-type < number-type ;
88 TUPLE: real-complex-type < complex-type ;
89 TUPLE: double-complex-type < complex-type ;
90
91 CONSTANT: fortran>c-types H{
92     { "character"        character-type        }
93     { "integer"          integer-type          }
94     { "logical"          logical-type          }
95     { "real"             real-type             }
96     { "double-precision" double-precision-type }
97     { "complex"          real-complex-type     }
98     { "double-complex"   double-complex-type   }
99 }
100
101 : append-dimensions ( base-c-type type -- c-type )
102     dims>> [ product 2array ] when* ;
103
104 MACRO: size-case-type ( cases -- quot )
105     [ invalid-fortran-type ] suffix
106     '[ [ size>> _ case ] [ append-dimensions ] bi ] ;
107
108 : simple-type ( type base-c-type -- c-type )
109     swap
110     [ dup size>> [ invalid-fortran-type ] [ drop ] if ]
111     [ append-dimensions ] bi ;
112
113 : new-fortran-type ( out? dims size class -- type )
114     new [ [ size<< ] [ dims<< ] [ out?<< ] tri ] keep ;
115
116 GENERIC: (fortran-type>c-type) ( type -- c-type )
117
118 M: f (fortran-type>c-type) drop c:void ;
119
120 M: integer-type (fortran-type>c-type)
121     {
122         { f [ c:int      ] }
123         { 1 [ c:char     ] }
124         { 2 [ c:short    ] }
125         { 4 [ c:int      ] }
126         { 8 [ c:longlong ] }
127     } size-case-type ;
128 M: real-type (fortran-type>c-type)
129     {
130         { f [ c:float  ] }
131         { 4 [ c:float  ] }
132         { 8 [ c:double ] }
133     } size-case-type ;
134 M: real-complex-type (fortran-type>c-type)
135     {
136         {  f [ complex-float  ] }
137         {  8 [ complex-float  ] }
138         { 16 [ complex-double ] }
139     } size-case-type ;
140
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 ;
147
148 : single-char? ( character-type -- ? )
149     { [ drop character(1)-maps-to-char? ] [ dims>> product 1 = ] } 1&& ;
150
151 : fix-character-type ( character-type -- character-type' )
152     clone dup size>>
153     [ dup dims>> [ invalid-fortran-type ] [ dup size>> 1array >>dims f >>size ] if ]
154     [ dup dims>> [ ] [ f >>dims ] if ] if
155     dup single-char? [ f >>dims ] when ;
156
157 M: character-type (fortran-type>c-type)
158     fix-character-type c:char simple-type ;
159
160 : dimension>number ( string -- number )
161     dup "*" = [ drop 0 ] [ string>number ] if ;
162
163 : parse-out ( string -- string' out? )
164     "!" ?head ;
165
166 : parse-dims ( string -- string' dim )
167     "(" split1 dup
168     [ ")" ?tail drop "," split [ [ blank? ] trim dimension>number ] map ] when ;
169
170 : parse-size ( string -- string' size )
171     "*" split1 dup [ string>number ] when ;
172
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 ;
177
178 : parse-fortran-type ( fortran-type-string/f -- type/f )
179     dup [ (parse-fortran-type) ] when ;
180
181 GENERIC: added-c-args ( type -- args )
182
183 M: fortran-type added-c-args drop { } ;
184 M: character-type added-c-args fix-character-type single-char? [ { } ] [ { c:long } ] if ;
185
186 GENERIC: returns-by-value? ( type -- ? )
187
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&& ;
194
195 GENERIC: (fortran-ret-type>c-type) ( type -- c-type )
196
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 ;
201
202 GENERIC: (fortran-arg>c-args) ( type -- main-quot added-quot )
203
204 : args?dims ( type quot -- main-quot added-quot )
205     [ dup dims>> [ drop [ ] [ drop ] ] ] dip if ; inline
206
207 M: integer-type (fortran-arg>c-args)
208     [
209         size>> {
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             [ invalid-fortran-type ]
216         } case
217     ] args?dims ;
218
219 M: logical-type (fortran-arg>c-args)
220     [ call-next-method [ [ 1 0 ? ] prepend ] dip ] args?dims ;
221
222 M: real-type (fortran-arg>c-args)
223     [
224         size>> {
225             { f [ [ c:float <ref> ] [ drop ] ] }
226             { 4 [ [ c:float <ref> ] [ drop ] ] }
227             { 8 [ [ c:double <ref> ] [ drop ] ] }
228             [ invalid-fortran-type ]
229         } case
230     ] args?dims ;
231
232 M: real-complex-type (fortran-arg>c-args)
233     [
234         size>> {
235             {  f [ [ <complex-float>  ] [ drop ] ] }
236             {  8 [ [ <complex-float>  ] [ drop ] ] }
237             { 16 [ [ <complex-double> ] [ drop ] ] }
238             [ invalid-fortran-type ]
239         } case
240     ] args?dims ;
241
242 M: double-precision-type (fortran-arg>c-args)
243     [ drop [ c:double <ref> ] [ drop ] ] args?dims ;
244
245 M: double-complex-type (fortran-arg>c-args)
246     [ drop [ <complex-double> ] [ drop ] ] args?dims ;
247
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 ;
252
253 M: misc-type (fortran-arg>c-args)
254     drop [ ] [ drop ] ;
255
256 GENERIC: (fortran-result>) ( type -- quots )
257
258 : result?dims ( type quot -- quot )
259     [ dup dims>> [ drop { [ ] } ] ] dip if ; inline
260
261 M: integer-type (fortran-result>)
262     [
263         size>> {
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             [ invalid-fortran-type ]
270         } case
271     ] result?dims ;
272
273 M: logical-type (fortran-result>)
274     [ call-next-method first [ zero? not ] append 1array ] result?dims ;
275
276 M: real-type (fortran-result>)
277     [ size>> {
278         { f [ { [ c:float deref ] } ] }
279         { 4 [ { [ c:float deref ] } ] }
280         { 8 [ { [ c:double deref ] } ] }
281         [ invalid-fortran-type ]
282     } case ] result?dims ;
283
284 M: real-complex-type (fortran-result>)
285     [ size>> {
286         {  f [ { [ *complex-float  ] } ] }
287         {  8 [ { [ *complex-float  ] } ] }
288         { 16 [ { [ *complex-double ] } ] }
289         [ invalid-fortran-type ]
290     } case ] result?dims ;
291
292 M: double-precision-type (fortran-result>)
293     [ drop { [ c:double deref ] } ] result?dims ;
294
295 M: double-complex-type (fortran-result>)
296     [ drop { [ *complex-double ] } ] result?dims ;
297
298 M: character-type (fortran-result>)
299     fix-character-type single-char?
300     [ { [ c:char deref 1string ] } ]
301     [ { [ ] [ ascii alien>nstring ] } ] if ;
302
303 M: misc-type (fortran-result>)
304     drop { [ ] } ;
305
306 GENERIC: (<fortran-result>) ( type -- quot )
307
308 M: fortran-type (<fortran-result>)
309     (fortran-type>c-type) \ heap-size \ <byte-array> [ ] 3sequence ;
310
311 M: character-type (<fortran-result>)
312     fix-character-type dims>> product dup
313     [ \ <byte-array> ] dip [ ] 3sequence ;
314
315 : [<fortran-result>] ( return parameters -- quot )
316     [ parse-fortran-type ] dip
317     over returns-by-value?
318     [ 2drop [ ] ]
319     [ [ (<fortran-result>) ] [ length \ ndip [ ] 3sequence ] bi* ] if ;
320
321 : [fortran-args>c-args] ( parameters -- quot )
322     [ [ ] ] [
323         [ parse-fortran-type (fortran-arg>c-args) 2array ] map flip first2
324         [ [ \ spread [ ] 2sequence ] bi@ 2array ] [ length ] bi
325         \ ncleave [ ] 3sequence
326     ] if-empty ;
327
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
331     [args>args]
332     c-return library c-function c-parameters \ alien-invoke
333     5 [ ] nsequence
334     c-parameters length \ nkeep
335     [ ] 3sequence ;
336
337 : [fortran-out-param>] ( parameter -- quot )
338     parse-fortran-type
339     [ (fortran-result>) ] [ out?>> ] bi
340     [ ] [ [ drop [ drop ] ] map ] if ;
341
342 : [fortran-return>] ( return -- quot )
343     parse-fortran-type {
344         { [ dup not ] [ drop { } ] }
345         { [ dup returns-by-value? ] [ drop { [ ] } ] }
346         [ (fortran-result>) ]
347     } cond ;
348
349 : letters ( -- seq ) CHAR: a CHAR: z [a,b] ;
350
351 : (shuffle-map) ( return parameters -- ret par )
352     [
353         fortran-ret-type>c-type length swap void? [ 1 + ] unless
354         letters swap head [ "ret" swap suffix ] map
355     ] [
356         [ fortran-arg-type>c-type nip length 1 + ] map letters swap zip
357         [ first2 letters swap head [ "" 2sequence ] with map ] map concat
358     ] bi* ;
359
360 : (fortran-in-shuffle) ( ret par -- seq )
361     [ second ] sort-with append ;
362
363 : (fortran-out-shuffle) ( ret par -- seq )
364     append ;
365
366 : [fortran-result-shuffle] ( return parameters -- quot )
367     (shuffle-map) [ (fortran-in-shuffle) ] [ (fortran-out-shuffle) ] 2bi <effect>
368     \ shuffle-effect [ ] 2sequence ;
369
370 : [fortran-results>] ( return parameters -- quot )
371     [ [fortran-result-shuffle] ]
372     [ drop [fortran-return>] ]
373     [ nip [ [fortran-out-param>] ] map concat ] 2tri
374     append
375     \ spread [ ] 2sequence append ;
376
377 : (add-fortran-library) ( fortran-abi name -- )
378     library-fortran-abis get-global set-at ;
379
380 PRIVATE>
381
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 ;
385
386 : fortran-name>symbol-name ( fortran-name -- c-name )
387     mangle-name ;
388
389 : fortran-type>c-type ( fortran-type -- c-type )
390     parse-fortran-type (fortran-type>c-type) ;
391
392 : fortran-arg-type>c-type ( fortran-type -- c-type added-args )
393     parse-fortran-type
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) { } ] [
399         c:void swap
400         [ added-c-args ] [ (fortran-type>c-type) <pointer> ] bi prefix
401     ] if ;
402
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
406     append >array ;
407
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 ;
410
411 : set-fortran-abi ( library -- )
412     library-fortran-abis get-global at fortran-abi set ;
413
414 : ((fortran-invoke)) ( return library function parameters -- quot )
415     {
416         [ 2nip [<fortran-result>] ]
417         [ nip nip nip [fortran-args>c-args] ]
418         [ [fortran-invoke] ]
419         [ 2nip [fortran-results>] ]
420     } 4 ncleave 4 nappend ;
421
422 :: (fortran-invoke) ( return library function parameters -- quot )
423     library library-fortran-abis get-global at dup bad-fortran-abi?
424     [ '[ _ throw ] ]
425     [ drop return library function parameters ((fortran-invoke)) ] if ;
426
427 MACRO: fortran-invoke ( return library function parameters -- quot )
428     { [ 2drop nip set-fortran-abi ] [ (fortran-invoke) ] } 4 ncleave ;
429
430 : parse-arglist ( parameters return -- types effect )
431     [
432         2 group
433         [ unzip [ "," ?tail drop ] map ]
434         [ [ first "!" head? ] filter [ second "," ?tail drop "'" append ] map ] bi
435     ] [ [ ] [ prefix ] if-void ]
436     bi* <effect> ;
437
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 ;
442
443 SYNTAX: SUBROUTINE:
444     f current-library get scan-token ")" parse-tokens
445     [ "()" subseq? ] reject define-fortran-function ;
446
447 SYNTAX: FUNCTION:
448     scan-token current-library get scan-token ")" parse-tokens
449     [ "()" subseq? ] reject define-fortran-function ;
450
451 SYNTAX: LIBRARY:
452     scan-token
453     [ current-library set ]
454     [ set-fortran-abi ] bi ;