| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 # | |
| 3 # Copyright (C) 2013 Google Inc. All rights reserved. | |
| 4 # | |
| 5 # Redistribution and use in source and binary forms, with or without | |
| 6 # modification, are permitted provided that the following conditions are | |
| 7 # met: | |
| 8 # | |
| 9 # * Redistributions of source code must retain the above copyright | |
| 10 # notice, this list of conditions and the following disclaimer. | |
| 11 # * Redistributions in binary form must reproduce the above | |
| 12 # copyright notice, this list of conditions and the following disclaimer | |
| 13 # in the documentation and/or other materials provided with the | |
| 14 # distribution. | |
| 15 # * Neither the name of Google Inc. nor the names of its | |
| 16 # contributors may be used to endorse or promote products derived from | |
| 17 # this software without specific prior written permission. | |
| 18 # | |
| 19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 30 | |
| 31 import optparse | |
| 32 import os | |
| 33 import cPickle as pickle | |
| 34 import posixpath | |
| 35 import re | |
| 36 import string | |
| 37 | |
| 38 module_path = os.path.dirname(__file__) | |
| 39 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir)) | |
| 40 | |
| 41 INHERITED_EXTENDED_ATTRIBUTES = set([ | |
| 42 'ActiveDOMObject', | |
| 43 'DependentLifetime', | |
| 44 'WillBeGarbageCollected', | |
| 45 ]) | |
| 46 | |
| 47 | |
| 48 # interfaces_info is *exported* (in a pickle), and should only contain data | |
| 49 # about an interface that contains paths or is needed by *other* interfaces, | |
| 50 # i.e., file layout data (to abstract the compiler from file paths) or | |
| 51 # public data (to avoid having to read other interfaces unnecessarily). | |
| 52 # It should *not* contain full information about an interface (e.g., all | |
| 53 # extended attributes), as this would cause unnecessary rebuilds. | |
| 54 interfaces_info = {} | |
| 55 | |
| 56 # Auxiliary variables (not visible to future build steps) | |
| 57 partial_interface_files = {} | |
| 58 parent_interfaces = {} | |
| 59 extended_attributes_by_interface = {} # interface name -> extended attributes | |
| 60 | |
| 61 | |
| 62 class IdlBadFilenameError(Exception): | |
| 63 """Raised if an IDL filename disagrees with the interface name in the file."
"" | |
| 64 pass | |
| 65 | |
| 66 | |
| 67 class IdlInterfaceFileNotFoundError(Exception): | |
| 68 """Raised if the IDL file implementing an interface cannot be found.""" | |
| 69 pass | |
| 70 | |
| 71 | |
| 72 def parse_options(): | |
| 73 usage = 'Usage: %prog [options] [generated1.idl]...' | |
| 74 parser = optparse.OptionParser(usage=usage) | |
| 75 parser.add_option('--event-names-file', help='output file') | |
| 76 parser.add_option('--idl-files-list', help='file listing IDL files') | |
| 77 parser.add_option('--interface-dependencies-file', help='output file') | |
| 78 parser.add_option('--interfaces-info-file', help='output pickle file') | |
| 79 parser.add_option('--window-constructors-file', help='output file') | |
| 80 parser.add_option('--workerglobalscope-constructors-file', help='output file
') | |
| 81 parser.add_option('--sharedworkerglobalscope-constructors-file', help='outpu
t file') | |
| 82 parser.add_option('--dedicatedworkerglobalscope-constructors-file', help='ou
tput file') | |
| 83 parser.add_option('--serviceworkerglobalscope-constructors-file', help='outp
ut file') | |
| 84 parser.add_option('--write-file-only-if-changed', type='int', help='if true,
do not write an output file if it would be identical to the existing one, which
avoids unnecessary rebuilds in ninja') | |
| 85 options, args = parser.parse_args() | |
| 86 if options.event_names_file is None: | |
| 87 parser.error('Must specify an output file using --event-names-file.') | |
| 88 if options.interface_dependencies_file is None: | |
| 89 parser.error('Must specify an output file using --interface-dependencies
-file.') | |
| 90 if options.interfaces_info_file is None: | |
| 91 parser.error('Must specify an output file using --interfaces-info-file.'
) | |
| 92 if options.window_constructors_file is None: | |
| 93 parser.error('Must specify an output file using --window-constructors-fi
le.') | |
| 94 if options.workerglobalscope_constructors_file is None: | |
| 95 parser.error('Must specify an output file using --workerglobalscope-cons
tructors-file.') | |
| 96 if options.sharedworkerglobalscope_constructors_file is None: | |
| 97 parser.error('Must specify an output file using --sharedworkerglobalscop
e-constructors-file.') | |
| 98 if options.dedicatedworkerglobalscope_constructors_file is None: | |
| 99 parser.error('Must specify an output file using --dedicatedworkerglobals
cope-constructors-file.') | |
| 100 if options.serviceworkerglobalscope_constructors_file is None: | |
| 101 parser.error('Must specify an output file using --serviceworkerglobalsco
pe-constructors-file.') | |
| 102 if options.idl_files_list is None: | |
| 103 parser.error('Must specify a file listing IDL files using --idl-files-li
st.') | |
| 104 if options.write_file_only_if_changed is None: | |
| 105 parser.error('Must specify whether file is only written if changed using
--write-file-only-if-changed.') | |
| 106 options.write_file_only_if_changed = bool(options.write_file_only_if_changed
) | |
| 107 return options, args | |
| 108 | |
| 109 | |
| 110 ################################################################################ | |
| 111 # Basic file reading/writing | |
| 112 ################################################################################ | |
| 113 | |
| 114 def get_file_contents(idl_filename): | |
| 115 with open(idl_filename) as idl_file: | |
| 116 lines = idl_file.readlines() | |
| 117 return ''.join(lines) | |
| 118 | |
| 119 | |
| 120 def write_file(new_lines, destination_filename, only_if_changed): | |
| 121 if only_if_changed and os.path.isfile(destination_filename): | |
| 122 with open(destination_filename) as destination_file: | |
| 123 if destination_file.readlines() == new_lines: | |
| 124 return | |
| 125 with open(destination_filename, 'w') as destination_file: | |
| 126 destination_file.write(''.join(new_lines)) | |
| 127 | |
| 128 | |
| 129 def write_pickle_file(pickle_filename, data, only_if_changed): | |
| 130 if only_if_changed and os.path.isfile(pickle_filename): | |
| 131 with open(pickle_filename) as pickle_file: | |
| 132 if pickle.load(pickle_file) == data: | |
| 133 return | |
| 134 with open(pickle_filename, 'w') as pickle_file: | |
| 135 pickle.dump(data, pickle_file) | |
| 136 | |
| 137 | |
| 138 ################################################################################ | |
| 139 # IDL parsing | |
| 140 # | |
| 141 # We use regular expressions for parsing; this is incorrect (Web IDL is not a | |
| 142 # regular language), but simple and sufficient in practice. | |
| 143 # Leading and trailing context (e.g. following '{') used to avoid false matches. | |
| 144 ################################################################################ | |
| 145 | |
| 146 def get_partial_interface_name_from_idl(file_contents): | |
| 147 match = re.search(r'partial\s+interface\s+(\w+)\s*{', file_contents) | |
| 148 return match and match.group(1) | |
| 149 | |
| 150 | |
| 151 # identifier-A implements identifier-B; | |
| 152 # http://www.w3.org/TR/WebIDL/#idl-implements-statements | |
| 153 def get_implemented_interfaces_from_idl(file_contents, interface_name): | |
| 154 def get_implemented(left_identifier, right_identifier): | |
| 155 # identifier-A must be the current interface | |
| 156 if left_identifier != interface_name: | |
| 157 raise IdlBadFilenameError("Identifier on the left of the 'implements
' statement should be %s in %s.idl, but found %s" % (interface_name, interface_n
ame, left_identifier)) | |
| 158 return right_identifier | |
| 159 | |
| 160 implements_re = (r'^\s*' | |
| 161 r'(\w+)\s+' | |
| 162 r'implements\s+' | |
| 163 r'(\w+)\s*' | |
| 164 r';') | |
| 165 implements_matches = re.finditer(implements_re, file_contents, re.MULTILINE) | |
| 166 implements_pairs = [(match.group(1), match.group(2)) | |
| 167 for match in implements_matches] | |
| 168 return [get_implemented(left, right) for left, right in implements_pairs] | |
| 169 | |
| 170 | |
| 171 def is_callback_interface_from_idl(file_contents): | |
| 172 match = re.search(r'callback\s+interface\s+\w+\s*{', file_contents) | |
| 173 return bool(match) | |
| 174 | |
| 175 | |
| 176 def get_parent_interface(file_contents): | |
| 177 match = re.search(r'interface\s+' | |
| 178 r'\w+\s*' | |
| 179 r':\s*(\w+)\s*' | |
| 180 r'{', | |
| 181 file_contents) | |
| 182 return match and match.group(1) | |
| 183 | |
| 184 | |
| 185 def get_interface_extended_attributes_from_idl(file_contents): | |
| 186 match = re.search(r'\[(.*)\]\s*' | |
| 187 r'((callback|partial)\s+)?' | |
| 188 r'(interface|exception)\s+' | |
| 189 r'\w+\s*' | |
| 190 r'(:\s*\w+\s*)?' | |
| 191 r'{', | |
| 192 file_contents, flags=re.DOTALL) | |
| 193 if not match: | |
| 194 return {} | |
| 195 # Strip comments | |
| 196 # re.compile needed b/c Python 2.6 doesn't support flags in re.sub | |
| 197 single_line_comment_re = re.compile(r'//.*$', flags=re.MULTILINE) | |
| 198 block_comment_re = re.compile(r'/\*.*?\*/', flags=re.MULTILINE | re.DOTALL) | |
| 199 extended_attributes_string = re.sub(single_line_comment_re, '', match.group(
1)) | |
| 200 extended_attributes_string = re.sub(block_comment_re, '', extended_attribute
s_string) | |
| 201 extended_attributes = {} | |
| 202 # FIXME: this splitting is WRONG: it fails on ExtendedAttributeArgList like | |
| 203 # 'NamedConstructor=Foo(a, b)' | |
| 204 parts = [extended_attribute.strip() | |
| 205 for extended_attribute in extended_attributes_string.split(',') | |
| 206 # Discard empty parts, which may exist due to trailing comma | |
| 207 if extended_attribute.strip()] | |
| 208 for part in parts: | |
| 209 name, _, value = map(string.strip, part.partition('=')) | |
| 210 extended_attributes[name] = value | |
| 211 return extended_attributes | |
| 212 | |
| 213 | |
| 214 def get_put_forward_interfaces_from_idl(file_contents): | |
| 215 put_forwards_pattern = (r'\[[^\]]*PutForwards=[^\]]*\]\s+' | |
| 216 r'readonly\s+' | |
| 217 r'attribute\s+' | |
| 218 r'(\w+)') | |
| 219 return sorted(set(match.group(1) | |
| 220 for match in re.finditer(put_forwards_pattern, | |
| 221 file_contents, | |
| 222 flags=re.DOTALL))) | |
| 223 | |
| 224 | |
| 225 ################################################################################ | |
| 226 # Write files | |
| 227 ################################################################################ | |
| 228 | |
| 229 def write_dependencies_file(dependencies_filename, only_if_changed): | |
| 230 """Write the interface dependencies file. | |
| 231 | |
| 232 The format is as follows: | |
| 233 | |
| 234 Document.idl P.idl | |
| 235 Event.idl | |
| 236 Window.idl Q.idl R.idl S.idl | |
| 237 ... | |
| 238 | |
| 239 The above indicates that: | |
| 240 Document.idl depends on P.idl, | |
| 241 Event.idl depends on no other IDL files, and | |
| 242 Window.idl depends on Q.idl, R.idl, and S.idl. | |
| 243 | |
| 244 An IDL that is a dependency of another IDL (e.g. P.idl) does not have its | |
| 245 own line in the dependency file. | |
| 246 """ | |
| 247 # FIXME: remove text format once Perl gone (Python uses pickle) | |
| 248 dependencies_list = sorted( | |
| 249 (interface_info['full_path'], sorted(interface_info['dependencies_full_p
aths'])) | |
| 250 for interface_info in interfaces_info.values()) | |
| 251 lines = ['%s %s\n' % (idl_file, ' '.join(dependency_files)) | |
| 252 for idl_file, dependency_files in dependencies_list] | |
| 253 write_file(lines, dependencies_filename, only_if_changed) | |
| 254 | |
| 255 | |
| 256 def write_event_names_file(destination_filename, only_if_changed): | |
| 257 # Generate event names for all interfaces that inherit from Event, | |
| 258 # including Event itself. | |
| 259 event_names = set( | |
| 260 interface_name | |
| 261 for interface_name, interface_info in interfaces_info.iteritems() | |
| 262 if (interface_name == 'Event' or | |
| 263 ('ancestors' in interface_info and | |
| 264 interface_info['ancestors'][-1] == 'Event'))) | |
| 265 | |
| 266 def extended_attribute_string(name): | |
| 267 value = extended_attributes[name] | |
| 268 if name == 'RuntimeEnabled': | |
| 269 value += 'Enabled' | |
| 270 return name + '=' + value | |
| 271 | |
| 272 source_dir, _ = os.path.split(os.getcwd()) | |
| 273 lines = [] | |
| 274 lines.append('namespace="Event"\n') | |
| 275 lines.append('\n') | |
| 276 for filename, extended_attributes in sorted( | |
| 277 (interface_info['full_path'], | |
| 278 extended_attributes_by_interface[interface_name]) | |
| 279 for interface_name, interface_info in interfaces_info.iteritems() | |
| 280 if interface_name in event_names): | |
| 281 refined_filename, _ = os.path.splitext(os.path.relpath(filename, source_
dir)) | |
| 282 refined_filename = refined_filename.replace(os.sep, posixpath.sep) | |
| 283 extended_attributes_list = [ | |
| 284 extended_attribute_string(name) | |
| 285 for name in 'Conditional', 'ImplementedAs', 'RuntimeEnabled' | |
| 286 if name in extended_attributes] | |
| 287 lines.append('%s %s\n' % (refined_filename, ', '.join(extended_attribute
s_list))) | |
| 288 write_file(lines, destination_filename, only_if_changed) | |
| 289 | |
| 290 | |
| 291 def write_global_constructors_partial_interface(interface_name, destination_file
name, constructor_attributes_list, only_if_changed): | |
| 292 lines = (['partial interface %s {\n' % interface_name] + | |
| 293 [' %s;\n' % constructor_attribute | |
| 294 for constructor_attribute in sorted(constructor_attributes_list)]
+ | |
| 295 ['};\n']) | |
| 296 write_file(lines, destination_filename, only_if_changed) | |
| 297 | |
| 298 | |
| 299 ################################################################################ | |
| 300 # Dependency resolution | |
| 301 ################################################################################ | |
| 302 | |
| 303 def include_path(idl_filename, implemented_as=None): | |
| 304 """Returns relative path to header file in POSIX format; used in includes. | |
| 305 | |
| 306 POSIX format is used for consistency of output, so reference tests are | |
| 307 platform-independent. | |
| 308 """ | |
| 309 relative_path_local = os.path.relpath(idl_filename, source_path) | |
| 310 relative_dir_local = os.path.dirname(relative_path_local) | |
| 311 relative_dir_posix = relative_dir_local.replace(os.path.sep, posixpath.sep) | |
| 312 | |
| 313 idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename)) | |
| 314 cpp_class_name = implemented_as or idl_file_basename | |
| 315 | |
| 316 return posixpath.join(relative_dir_posix, cpp_class_name + '.h') | |
| 317 | |
| 318 | |
| 319 def add_paths_to_partials_dict(partial_interface_name, full_path, this_include_p
ath=None): | |
| 320 paths_dict = partial_interface_files.setdefault(partial_interface_name, | |
| 321 {'full_paths': [], | |
| 322 'include_paths': []}) | |
| 323 paths_dict['full_paths'].append(full_path) | |
| 324 if this_include_path: | |
| 325 paths_dict['include_paths'].append(this_include_path) | |
| 326 | |
| 327 | |
| 328 def generate_dependencies(idl_filename): | |
| 329 """Compute dependencies for IDL file, returning True if main (non-partial) i
nterface""" | |
| 330 full_path = os.path.realpath(idl_filename) | |
| 331 idl_file_contents = get_file_contents(full_path) | |
| 332 | |
| 333 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co
ntents) | |
| 334 implemented_as = extended_attributes.get('ImplementedAs') | |
| 335 # FIXME: remove [NoHeader] once switch to Python | |
| 336 this_include_path = (include_path(idl_filename, implemented_as) | |
| 337 if 'NoHeader' not in extended_attributes else None) | |
| 338 | |
| 339 # Handle partial interfaces | |
| 340 partial_interface_name = get_partial_interface_name_from_idl(idl_file_conten
ts) | |
| 341 if partial_interface_name: | |
| 342 add_paths_to_partials_dict(partial_interface_name, full_path, this_inclu
de_path) | |
| 343 return False | |
| 344 | |
| 345 # If not a partial interface, the basename is the interface name | |
| 346 interface_name, _ = os.path.splitext(os.path.basename(idl_filename)) | |
| 347 | |
| 348 interfaces_info[interface_name] = { | |
| 349 'full_path': full_path, | |
| 350 'implements_interfaces': get_implemented_interfaces_from_idl(idl_file_co
ntents, interface_name), | |
| 351 'is_callback_interface': is_callback_interface_from_idl(idl_file_content
s), | |
| 352 # Interfaces that are referenced (used as types) and that we introspect | |
| 353 # during code generation (beyond interface-level data ([ImplementedAs], | |
| 354 # is_callback_interface, ancestors, and inherited extended attributes): | |
| 355 # deep dependencies. | |
| 356 # These cause rebuilds of referrers, due to the dependency, so these | |
| 357 # should be minimized; currently only targets of [PutForwards]. | |
| 358 'referenced_interfaces': get_put_forward_interfaces_from_idl(idl_file_co
ntents), | |
| 359 } | |
| 360 if this_include_path: | |
| 361 interfaces_info[interface_name]['include_path'] = this_include_path | |
| 362 if implemented_as: | |
| 363 interfaces_info[interface_name]['implemented_as'] = implemented_as | |
| 364 | |
| 365 return True | |
| 366 | |
| 367 | |
| 368 def generate_constructor_attribute_list(interface_name, extended_attributes): | |
| 369 extended_attributes_list = [ | |
| 370 name + '=' + extended_attributes[name] | |
| 371 for name in 'Conditional', 'PerContextEnabled', 'RuntimeEnabled' | |
| 372 if name in extended_attributes] | |
| 373 if extended_attributes_list: | |
| 374 extended_string = '[%s] ' % ', '.join(extended_attributes_list) | |
| 375 else: | |
| 376 extended_string = '' | |
| 377 | |
| 378 attribute_string = 'attribute {interface_name}Constructor {interface_name}'.
format(interface_name=interface_name) | |
| 379 attributes_list = [extended_string + attribute_string] | |
| 380 | |
| 381 # In addition to the regular property, for every [NamedConstructor] | |
| 382 # extended attribute on an interface, a corresponding property MUST exist | |
| 383 # on the ECMAScript global object. | |
| 384 if 'NamedConstructor' in extended_attributes: | |
| 385 named_constructor = extended_attributes['NamedConstructor'] | |
| 386 # Extract function name, namely everything before opening '(' | |
| 387 constructor_name = re.sub(r'\(.*', '', named_constructor) | |
| 388 # Note the reduplicated 'ConstructorConstructor' | |
| 389 attribute_string = 'attribute %sConstructorConstructor %s' % (interface_
name, constructor_name) | |
| 390 attributes_list.append(extended_string + attribute_string) | |
| 391 | |
| 392 return attributes_list | |
| 393 | |
| 394 | |
| 395 def record_global_constructors_and_extended_attributes(idl_filename, global_cons
tructors): | |
| 396 interface_name, _ = os.path.splitext(os.path.basename(idl_filename)) | |
| 397 full_path = os.path.realpath(idl_filename) | |
| 398 idl_file_contents = get_file_contents(full_path) | |
| 399 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co
ntents) | |
| 400 | |
| 401 # Record extended attributes | |
| 402 extended_attributes_by_interface[interface_name] = extended_attributes | |
| 403 | |
| 404 # Record global constructors | |
| 405 if (not is_callback_interface_from_idl(idl_file_contents) and | |
| 406 'NoInterfaceObject' not in extended_attributes): | |
| 407 global_contexts = extended_attributes.get('GlobalContext', 'Window').spl
it('&') | |
| 408 new_constructor_list = generate_constructor_attribute_list(interface_nam
e, extended_attributes) | |
| 409 for global_object in global_contexts: | |
| 410 global_constructors[global_object].extend(new_constructor_list) | |
| 411 | |
| 412 # Record parents | |
| 413 parent = get_parent_interface(idl_file_contents) | |
| 414 if parent: | |
| 415 parent_interfaces[interface_name] = parent | |
| 416 | |
| 417 | |
| 418 def record_extended_attributes(idl_filename): | |
| 419 interface_name, _ = os.path.splitext(os.path.basename(idl_filename)) | |
| 420 full_path = os.path.realpath(idl_filename) | |
| 421 idl_file_contents = get_file_contents(full_path) | |
| 422 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co
ntents) | |
| 423 extended_attributes_by_interface[interface_name] = extended_attributes | |
| 424 | |
| 425 | |
| 426 def generate_ancestors_and_inherited_extended_attributes(interface_name): | |
| 427 interface_info = interfaces_info[interface_name] | |
| 428 interface_extended_attributes = extended_attributes_by_interface[interface_n
ame] | |
| 429 inherited_extended_attributes = dict( | |
| 430 (key, value) | |
| 431 for key, value in interface_extended_attributes.iteritems() | |
| 432 if key in INHERITED_EXTENDED_ATTRIBUTES) | |
| 433 | |
| 434 def generate_ancestors(interface_name): | |
| 435 while interface_name in parent_interfaces: | |
| 436 interface_name = parent_interfaces[interface_name] | |
| 437 yield interface_name | |
| 438 | |
| 439 ancestors = list(generate_ancestors(interface_name)) | |
| 440 if not ancestors: | |
| 441 if inherited_extended_attributes: | |
| 442 interface_info['inherited_extended_attributes'] = inherited_extended
_attributes | |
| 443 return | |
| 444 | |
| 445 interface_info['ancestors'] = ancestors | |
| 446 for ancestor in ancestors: | |
| 447 # Extended attributes are missing if an ancestor is an interface that | |
| 448 # we're not processing, notably real IDL files if only processing test | |
| 449 # IDL files, or generated support files. | |
| 450 ancestor_extended_attributes = extended_attributes_by_interface.get(ance
stor, {}) | |
| 451 inherited_extended_attributes.update(dict( | |
| 452 (key, value) | |
| 453 for key, value in ancestor_extended_attributes.iteritems() | |
| 454 if key in INHERITED_EXTENDED_ATTRIBUTES)) | |
| 455 if inherited_extended_attributes: | |
| 456 interface_info['inherited_extended_attributes'] = inherited_extended_att
ributes | |
| 457 | |
| 458 | |
| 459 def parse_idl_files(idl_files, global_constructors_filenames): | |
| 460 """Compute dependencies between IDL files, and return constructors on global
objects. | |
| 461 | |
| 462 Primary effect is computing info about main interfaces, stored in global | |
| 463 interfaces_info. | |
| 464 The keys are the interfaces for which bindings are generated; | |
| 465 this does not include interfaces implemented by another interface. | |
| 466 | |
| 467 Returns: | |
| 468 global_constructors: | |
| 469 dict of global objects -> list of constructors on that object | |
| 470 """ | |
| 471 global_constructors = dict([ | |
| 472 (global_object, []) | |
| 473 for global_object in global_constructors_filenames]) | |
| 474 | |
| 475 # Generate dependencies, and (for main IDL files), record | |
| 476 # global_constructors and extended_attributes_by_interface. | |
| 477 for idl_filename in idl_files: | |
| 478 # Test skips partial interfaces | |
| 479 if generate_dependencies(idl_filename): | |
| 480 record_global_constructors_and_extended_attributes(idl_filename, glo
bal_constructors) | |
| 481 | |
| 482 for interface_name in interfaces_info: | |
| 483 generate_ancestors_and_inherited_extended_attributes(interface_name) | |
| 484 | |
| 485 # Add constructors on global objects to partial interfaces | |
| 486 # These are all partial interfaces, but the files are dynamically generated, | |
| 487 # so they need to be handled separately from static partial interfaces. | |
| 488 for global_object, constructor_filename in global_constructors_filenames.ite
ritems(): | |
| 489 if global_object in interfaces_info: | |
| 490 # No include path needed, as already included in the header file | |
| 491 add_paths_to_partials_dict(global_object, constructor_filename) | |
| 492 | |
| 493 # An IDL file's dependencies are partial interface files that extend it, | |
| 494 # and files for other interfaces that this interfaces implements. | |
| 495 for interface_name, interface_info in interfaces_info.iteritems(): | |
| 496 partial_interfaces_full_paths, partial_interfaces_include_paths = ( | |
| 497 (partial_interface_files[interface_name]['full_paths'], | |
| 498 partial_interface_files[interface_name]['include_paths']) | |
| 499 if interface_name in partial_interface_files else ([], [])) | |
| 500 | |
| 501 implemented_interfaces = interface_info['implements_interfaces'] | |
| 502 try: | |
| 503 implemented_interfaces_full_paths = [ | |
| 504 interfaces_info[interface]['full_path'] | |
| 505 for interface in implemented_interfaces] | |
| 506 implemented_interfaces_include_paths = [ | |
| 507 interfaces_info[interface]['include_path'] | |
| 508 for interface in implemented_interfaces | |
| 509 if 'include_path' in interfaces_info[interface]] | |
| 510 except KeyError as key_name: | |
| 511 raise IdlInterfaceFileNotFoundError('Could not find the IDL file whe
re the following implemented interface is defined: %s' % key_name) | |
| 512 | |
| 513 interface_info['dependencies_full_paths'] = ( | |
| 514 partial_interfaces_full_paths + | |
| 515 implemented_interfaces_full_paths) | |
| 516 interface_info['dependencies_include_paths'] = ( | |
| 517 partial_interfaces_include_paths + | |
| 518 implemented_interfaces_include_paths) | |
| 519 | |
| 520 return global_constructors | |
| 521 | |
| 522 | |
| 523 ################################################################################ | |
| 524 | |
| 525 def main(): | |
| 526 options, args = parse_options() | |
| 527 | |
| 528 # Static IDL files are passed in a file (generated at GYP time), due to OS | |
| 529 # command line length limits | |
| 530 with open(options.idl_files_list) as idl_files_list: | |
| 531 idl_files = [line.rstrip('\n') for line in idl_files_list] | |
| 532 # Generated IDL files are passed at the command line, since these are in the | |
| 533 # build directory, which is determined at build time, not GYP time, so these | |
| 534 # cannot be included in the file listing static files | |
| 535 idl_files.extend(args) | |
| 536 | |
| 537 only_if_changed = options.write_file_only_if_changed | |
| 538 global_constructors_filenames = { | |
| 539 'Window': options.window_constructors_file, | |
| 540 'WorkerGlobalScope': options.workerglobalscope_constructors_file, | |
| 541 'SharedWorkerGlobalScope': options.sharedworkerglobalscope_constructors_
file, | |
| 542 'DedicatedWorkerGlobalScope': options.dedicatedworkerglobalscope_constru
ctors_file, | |
| 543 'ServiceWorkerGlobalScope': options.serviceworkerglobalscope_constructor
s_file, | |
| 544 } | |
| 545 | |
| 546 global_constructors = parse_idl_files(idl_files, global_constructors_filenam
es) | |
| 547 | |
| 548 write_dependencies_file(options.interface_dependencies_file, only_if_changed
) | |
| 549 write_pickle_file(options.interfaces_info_file, interfaces_info, only_if_cha
nged) | |
| 550 for interface_name, filename in global_constructors_filenames.iteritems(): | |
| 551 if interface_name in interfaces_info: | |
| 552 write_global_constructors_partial_interface(interface_name, filename
, global_constructors[interface_name], only_if_changed) | |
| 553 write_event_names_file(options.event_names_file, only_if_changed) | |
| 554 | |
| 555 | |
| 556 if __name__ == '__main__': | |
| 557 main() | |
| OLD | NEW |