15
15
listed.
16
16
"""
17
17
from collections import namedtuple
18
+ import json
18
19
import re
19
20
from ompi_bindings import compiler , consts , util
20
21
from ompi_bindings .fortran_type import FortranType
21
22
22
23
23
24
FortranParameter = namedtuple ('FortranParameter' , ['type_name' , 'name' , 'dep_params' ])
24
- FortranPrototype = namedtuple ('FortranPrototype' , ['fn_name' , 'lno' , 'parameters' ])
25
-
26
-
27
- def parse_prototype (lno , line ):
28
- """Parse a prototype for the given line and string."""
29
- if consts .PROTOTYPE_RE .match (line ) is None :
30
- raise util .BindingError (
31
- f'Invalid function prototype for Fortran interface starting on line { lno } '
32
- )
33
-
34
- start = line .index ('(' )
35
- end = line .index (')' )
36
- fn_name = line [1 :start ].strip ()
37
- parameters = line [start + 1 :end ].split (',' )
38
-
39
- # Attempt to parse each parameter
40
- parsed_parameters = []
41
- try :
42
- for param in parameters :
43
- param = param .strip ()
44
- param_parts = param .split ()
45
- type_name = param_parts [0 ]
46
- name = '' .join (param_parts [1 :])
47
- type_ = FortranType .get (type_name )
48
- dep_params = None
49
-
50
- # Check for 'param[name=param(;name=param)]' parameters,
51
- # indicating a dependency on that other parameter
52
- if '[' in name :
53
- idx = name .index ('[' )
54
- dep_params = [part .split ('=' ) for part in name [idx + 1 :- 1 ].split (';' )]
55
- dep_params = dict (dep_params )
56
- name = name [:idx ]
57
-
58
- # Validate the parameter key values (or an empty list if not found)
59
- type_ .validate_dep_param_keys (name , [] if dep_params is None else dep_params .keys ())
60
-
61
- parsed_parameters .append (FortranParameter (type_name , name , dep_params ))
62
- return FortranPrototype (fn_name , lno , parsed_parameters )
63
- except util .BindingError as err :
64
- raise util .BindingError (
65
- f'Failed to parse prototype starting on line { lno } : { err } '
66
- ) from None
67
- except KeyError as err :
68
- raise util .BindingError (
69
- f'Found invalid type starting on line { lno } : { err } '
70
- ) from None
25
+ FortranPrototype = namedtuple ('FortranPrototype' , ['fn_name' , 'parameters' ])
71
26
72
27
73
28
def load_prototypes (fname ):
74
- """Load the prototypes from a file."""
29
+ """Load the prototypes from a JSON file."""
75
30
with open (fname ) as fp :
76
- tmp_proto_string = []
77
- proto_strings = []
78
- cur_lno = 0
79
- reading_proto = False
80
-
81
- # The loop below is designed to read in each prototype, each delimited
82
- # by a '.' preceding the name of the subroutine, allowing for the
83
- # prototype to run across multiple lines.
84
- for i , line in enumerate (fp ):
85
- lno = i + 1
86
- line = line .strip ()
87
-
88
- # First strip comments
89
- comm_idx = line .find ('#' )
90
- if comm_idx != - 1 :
91
- line = line [:comm_idx ]
92
- if not line :
93
- continue
94
-
95
- # Set the current line for the prototype
96
- if not tmp_proto_string :
97
- cur_lno = lno
98
-
99
- # Check for initial '.' character, indicating the start of a prototype
100
- reading_proto = reading_proto or line [0 ] == '.'
101
- if line [0 ] == '.' and tmp_proto_string :
102
- # If the buffer is not empty, then the previous prototype
103
- # string is complete and can be saved
104
- proto_strings .append ((cur_lno , ' ' .join (tmp_proto_string )))
105
- cur_lno = lno
106
- tmp_proto_string = []
107
- # Only add the line to the current buffer if we already encountered
108
- # a '.' at the start of this or a previous line
109
- if reading_proto :
110
- tmp_proto_string .append (line )
111
-
112
- if tmp_proto_string :
113
- proto_strings .append ((cur_lno , ' ' .join (tmp_proto_string )))
114
-
115
- return [parse_prototype (lno , proto_string ) for lno , proto_string in proto_strings ]
31
+ data = json .load (fp )
32
+ prototypes = []
33
+ for proto in data :
34
+ fn_name = proto ['name' ]
35
+ parameters = []
36
+ for param in proto ['parameters' ]:
37
+ type_name = param ['type' ]
38
+ type_ = FortranType .get (type_name )
39
+ param_name = param ['name' ]
40
+ dep_params = param ['dep_params' ] if 'dep_params' in param else None
41
+ try :
42
+ type_ .validate_dep_param_keys (param_name , [] if dep_params is None else dep_params .keys ())
43
+ except util .BindingError as err :
44
+ raise util .BindingError (f'Invalid prototype "{ fn_name } ": { err } ' ) from None
45
+ parameters .append (FortranParameter (type_name , param_name , dep_params ))
46
+ prototypes .append (FortranPrototype (fn_name , parameters ))
47
+ return prototypes
116
48
117
49
118
50
class FortranBinding :
@@ -136,13 +68,13 @@ def __init__(self, prototype, out, bigcount=False, ts=False):
136
68
if param .dep_params is not None :
137
69
dep_params [param .name ] = param .dep_params
138
70
# Set dependent parameters for those that need them
139
- try :
140
- for name , deps in dep_params . items () :
71
+ for name , deps in dep_params . items () :
72
+ try :
141
73
param_map [name ].dep_params = {key : param_map [dep_name ] for key , dep_name in deps .items ()}
142
- except KeyError as err :
143
- raise util .BindingError (
144
- f'Invalid dependent type in prototype starting on line { prototype .lno } : { err } '
145
- )
74
+ except KeyError as err :
75
+ raise util .BindingError (
76
+ f'Invalid dependent type for parameter " { name } " (prototype " { prototype .fn_name } ") : { err } '
77
+ ) from None
146
78
147
79
def dump (self , * pargs , ** kwargs ):
148
80
"""Write to the output file."""
@@ -370,7 +302,7 @@ def print_binding(prototype, lang, out, bigcount=False, ts=False):
370
302
371
303
def generate_code (args , out ):
372
304
"""Generate binding code based on arguments."""
373
- prototypes = load_prototypes (args .template )
305
+ prototypes = load_prototypes (args .prototypes )
374
306
if args .lang == 'fortran' :
375
307
print_f_source_header (out )
376
308
out .dump ()
@@ -388,7 +320,7 @@ def generate_code(args, out):
388
320
389
321
def generate_interface (args , out ):
390
322
"""Generate the Fortran interface files."""
391
- prototypes = load_prototypes (args .template )
323
+ prototypes = load_prototypes (args .prototypes )
392
324
out .dump (f'! { consts .GENERATED_MESSAGE } ' )
393
325
for prototype in prototypes :
394
326
ext_name = util .ext_api_func_name (prototype .fn_name )
0 commit comments