Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 1 | # |
| 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 | """ |
| 24 | usage: merge_driinfo.py <list of input files> |
| 25 | |
| 26 | Generates a source file which contains the DRI_CONF_xxx macros for generating |
| 27 | the driinfo XML that describes the available DriConf options for a driver and |
| 28 | its supported state trackers, based on the merged information from the input |
| 29 | files. |
| 30 | """ |
| 31 | |
| 32 | from __future__ import print_function |
| 33 | |
| 34 | import mako.template |
| 35 | import re |
| 36 | import sys |
| 37 | |
| 38 | |
| 39 | # Some regexps used during input parsing |
| 40 | RE_section_begin = re.compile(r'DRI_CONF_SECTION_(.*)') |
| 41 | RE_option = re.compile(r'DRI_CONF_(.*)\((.*)\)') |
| 42 | |
| 43 | |
| 44 | class 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ähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 55 | class 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ähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 63 | class 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 | |
| 74 | def 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ähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 86 | verbatim = None |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 87 | for line in infile: |
| 88 | linenum += 1 |
Nicolai Hähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 89 | |
| 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ähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 109 | 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 | |
| 165 | def 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ähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 176 | 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ähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 185 | else: |
Nicolai Hähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 186 | merged_section.options.append(orig_option) |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 187 | |
| 188 | return merged_section |
| 189 | |
| 190 | |
| 191 | def 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ähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 201 | if not isinstance(base_section, Section): |
| 202 | merged_sections.append(base_section) |
| 203 | continue |
| 204 | |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 205 | 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 | |
| 220 | def 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 | /* |
| 231 | Use as: |
| 232 | |
| 233 | #include "xmlpool.h" |
| 234 | |
| 235 | static const char driinfo_xml[] = |
| 236 | #include "this_file" |
| 237 | ; |
| 238 | */ |
| 239 | |
| 240 | DRI_CONF_BEGIN |
| 241 | % for section in sections: |
Nicolai Hähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 242 | % if isinstance(section, Section): |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 243 | DRI_CONF_SECTION_${section.name} |
| 244 | % for option in section.options: |
Nicolai Hähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 245 | % if isinstance(option, Option): |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 246 | DRI_CONF_${option.name}(${option.defaults}) |
Nicolai Hähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 247 | % else: |
| 248 | ${option.string} |
| 249 | % endif |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 250 | % endfor |
| 251 | DRI_CONF_SECTION_END |
Nicolai Hähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 252 | % else: |
| 253 | ${section.string} |
| 254 | % endif |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 255 | % endfor |
| 256 | DRI_CONF_END""") |
| 257 | |
Nicolai Hähnle | 8bef4df | 2019-03-15 14:56:36 +0100 | [diff] [blame^] | 258 | print(driinfo_h_template.render(sections=merged_sections_list, Section=Section, Option=Option)) |
Nicolai Hähnle | bfc26c4 | 2017-06-29 17:34:37 +0200 | [diff] [blame] | 259 | return True |
| 260 | |
| 261 | |
| 262 | if __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) |