blob: a09218a39021338450ed30d3c183b94f0ad27705 [file] [log] [blame]
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +02001#
2# Copyright 2017 Advanced Micro Devices, Inc.
3#
4# Permission is hereby granted, free of charge, to any person obtaining a
5# copy of this software and associated documentation files (the "Software"),
6# to deal in the Software without restriction, including without limitation
7# on the rights to use, copy, modify, merge, publish, distribute, sub
8# license, and/or sell copies of the Software, and to permit persons to whom
9# the Software is furnished to do so, subject to the following conditions:
10#
11# The above copyright notice and this permission notice (including the next
12# paragraph) shall be included in all copies or substantial portions of the
13# Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18# THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21# USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23"""
24usage: merge_driinfo.py <list of input files>
25
26Generates a source file which contains the DRI_CONF_xxx macros for generating
27the driinfo XML that describes the available DriConf options for a driver and
28its supported state trackers, based on the merged information from the input
29files.
30"""
31
32from __future__ import print_function
33
34import mako.template
35import re
36import sys
37
38
39# Some regexps used during input parsing
40RE_section_begin = re.compile(r'DRI_CONF_SECTION_(.*)')
41RE_option = re.compile(r'DRI_CONF_(.*)\((.*)\)')
42
43
44class Option(object):
45 """
46 Represent a config option as:
47 * name: the xxx part of the DRI_CONF_xxx macro
48 * defaults: the defaults parameters that are passed into the macro
49 """
50 def __init__(self, name, defaults):
51 self.name = name
52 self.defaults = defaults
53
54
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +010055class Verbatim(object):
56 """
57 Represent a chunk of code that is copied into the result file verbatim.
58 """
59 def __init__(self):
60 self.string = ''
61
62
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +020063class Section(object):
64 """
65 Represent a config section description as:
66 * name: the xxx part of the DRI_CONF_SECTION_xxx macro
67 * options: list of options
68 """
69 def __init__(self, name):
70 self.name = name
71 self.options = []
72
73
74def parse_inputs(input_filenames):
75 success = True
76 sections_lists = []
77
78 for input_filename in input_filenames:
79 with open(input_filename, 'r') as infile:
80 sections = []
81 sections_lists.append(sections)
82
83 section = None
84
85 linenum = 0
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +010086 verbatim = None
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +020087 for line in infile:
88 linenum += 1
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +010089
90 if line.startswith('//= BEGIN VERBATIM'):
91 if verbatim is not None:
92 print('{}:{}: nested verbatim'
93 .format(input_filename, linenum))
94 success = False
95 continue
96 verbatim = Verbatim()
97
98 if verbatim is not None:
99 verbatim.string += line
100
101 if line.startswith('//= END VERBATIM'):
102 if section is None:
103 sections.append(verbatim)
104 else:
105 section.options.append(verbatim)
106 verbatim = None
107 continue
108
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200109 line = line.strip()
110 if not line:
111 continue
112
113 if line.startswith('//'):
114 continue
115
116 if line == 'DRI_CONF_SECTION_END':
117 if section is None:
118 print('{}:{}: no open section'
119 .format(input_filename, linenum))
120 success = False
121 continue
122 section = None
123 continue
124
125 m = RE_section_begin.match(line)
126 if m:
127 if section is not None:
128 print('{}:{}: nested sections are not supported'
129 .format(input_filename, linenum))
130 success = False
131 continue
132 if sections is None:
133 print('{}:{}: missing DRIINFO line'
134 .format(input_filename, linenum))
135 success = False
136 break # parsing the rest really makes no sense
137 section = Section(m.group(1))
138 sections.append(section)
139 continue
140
141 m = RE_option.match(line)
142 if m:
143 if section is None:
144 print('{}:{}: no open section'
145 .format(input_filename, linenum))
146 success = False
147 break
148 section.options.append(Option(m.group(1), m.group(2)))
149 continue
150
151 print('{}:{}: do not understand this line'
152 .format(input_filename, linenum))
153 success = False
154
155 if section is not None:
156 print('{}:end-of-file: missing end of section'
157 .format(input_filename))
158 success = False
159
160 if success:
161 return sections_lists
162 return None
163
164
165def merge_sections(section_list):
166 """
167 section_list: list of Section objects to be merged, all of the same name
168 Return a merged Section object (everything is deeply copied)
169 """
170 merged_section = Section(section_list[0].name)
171
172 for section in section_list:
173 assert section.name == merged_section.name
174
175 for orig_option in section.options:
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100176 if isinstance(orig_option, Option):
177 for merged_option in merged_section.options:
178 if not isinstance(merged_option, Option):
179 continue
180 if orig_option.name == merged_option.name:
181 merged_option.defaults = orig_option.defaults
182 break
183 else:
184 merged_section.options.append(Option(orig_option.name, orig_option.defaults))
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200185 else:
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100186 merged_section.options.append(orig_option)
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200187
188 return merged_section
189
190
191def merge_sections_lists(sections_lists):
192 """
193 sections_lists: list of lists of Section objects to be merged
194 Return a merged list of merged Section objects; everything is deeply copied.
195 Default values for options in later lists override earlier default values.
196 """
197 merged_sections = []
198
199 for idx,sections in enumerate(sections_lists):
200 for base_section in sections:
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100201 if not isinstance(base_section, Section):
202 merged_sections.append(base_section)
203 continue
204
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200205 original_sections = [base_section]
206 for next_sections in sections_lists[idx+1:]:
207 for j,section in enumerate(next_sections):
208 if section.name == base_section.name:
209 original_sections.append(section)
210 del next_sections[j]
211 break
212
213 merged_section = merge_sections(original_sections)
214
215 merged_sections.append(merged_section)
216
217 return merged_sections
218
219
220def main(input_filenames):
221 sections_lists = parse_inputs(input_filenames)
222 if sections_lists is None:
223 return False
224
225 merged_sections_list = merge_sections_lists(sections_lists)
226
227 driinfo_h_template = mako.template.Template("""\
228// DO NOT EDIT - this file is automatically generated by merge_driinfo.py
229
230/*
231Use as:
232
233#include "xmlpool.h"
234
235static const char driinfo_xml[] =
236#include "this_file"
237;
238*/
239
240DRI_CONF_BEGIN
241% for section in sections:
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100242% if isinstance(section, Section):
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200243 DRI_CONF_SECTION_${section.name}
244% for option in section.options:
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100245% if isinstance(option, Option):
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200246 DRI_CONF_${option.name}(${option.defaults})
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100247% else:
248${option.string}
249% endif
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200250% endfor
251 DRI_CONF_SECTION_END
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100252% else:
253${section.string}
254% endif
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200255% endfor
256DRI_CONF_END""")
257
Nicolai Hähnle8bef4df2019-03-15 14:56:36 +0100258 print(driinfo_h_template.render(sections=merged_sections_list, Section=Section, Option=Option))
Nicolai Hähnlebfc26c42017-06-29 17:34:37 +0200259 return True
260
261
262if __name__ == '__main__':
263 if len(sys.argv) <= 1:
264 print('Missing arguments')
265 sys.exit(1)
266
267 if not main(sys.argv[1:]):
268 sys.exit(1)