Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: third_party/WebKit/Source/bindings/scripts/code_generator_v8.py

Issue 1961883002: Generate separate files for union type containers (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (C) 2013 Google Inc. All rights reserved. 1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer 10 # copyright notice, this list of conditions and the following disclaimer
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 IdlType.set_enums(info_provider.enumerations) 122 IdlType.set_enums(info_provider.enumerations)
123 IdlType.set_implemented_as_interfaces(interfaces_info['implemented_as_interf aces']) 123 IdlType.set_implemented_as_interfaces(interfaces_info['implemented_as_interf aces'])
124 IdlType.set_garbage_collected_types(interfaces_info['garbage_collected_inter faces']) 124 IdlType.set_garbage_collected_types(interfaces_info['garbage_collected_inter faces'])
125 v8_types.set_component_dirs(interfaces_info['component_dirs']) 125 v8_types.set_component_dirs(interfaces_info['component_dirs'])
126 126
127 127
128 def should_generate_code(definitions): 128 def should_generate_code(definitions):
129 return definitions.interfaces or definitions.dictionaries 129 return definitions.interfaces or definitions.dictionaries
130 130
131 131
132 def depends_on_union_types(idl_type): 132 def depending_union_type_name(idl_type):
133 """Returns true when a given idl_type depends on union containers 133 """Returns the union type name if the given idl_type depends on a
134 directly. 134 union type.
135 """ 135 """
136 if idl_type.is_union_type: 136 def find_base_type(current_type):
137 return True 137 if current_type.is_array_or_sequence_type:
138 if idl_type.is_array_or_sequence_type: 138 return find_base_type(current_type.element_type)
139 return idl_type.element_type.is_union_type 139 if current_type.is_nullable:
140 return False 140 return find_base_type(current_type.inner_type)
141 return current_type
142 base_type = find_base_type(idl_type)
143 if base_type.is_union_type:
144 return base_type.name
145 return None
141 146
142 147
143 class TypedefResolver(Visitor): 148 class TypedefResolver(Visitor):
144 def __init__(self, info_provider): 149 def __init__(self, info_provider):
145 self.info_provider = info_provider 150 self.info_provider = info_provider
146 151
147 def resolve(self, definitions, definition_name): 152 def resolve(self, definitions, definition_name):
148 """Traverse definitions and resolves typedefs with the actual types.""" 153 """Traverse definitions and resolves typedefs with the actual types."""
149 self.typedefs = {} 154 self.typedefs = {}
150 for name, typedef in self.info_provider.typedefs.iteritems(): 155 for name, typedef in self.info_provider.typedefs.iteritems():
151 self.typedefs[name] = typedef.idl_type 156 self.typedefs[name] = typedef.idl_type
152 self.additional_includes = set() 157 self.additional_header_includes = set()
153 definitions.accept(self) 158 definitions.accept(self)
154 self._update_dependencies_include_paths(definition_name) 159 self._update_dependencies_include_paths(definition_name)
155 160
156 def _update_dependencies_include_paths(self, definition_name): 161 def _update_dependencies_include_paths(self, definition_name):
157 interface_info = self.info_provider.interfaces_info[definition_name] 162 interface_info = self.info_provider.interfaces_info[definition_name]
158 dependencies_include_paths = interface_info['dependencies_include_paths' ] 163 interface_info['additional_header_includes'] = set(
159 for include_path in self.additional_includes: 164 self.additional_header_includes)
160 if include_path not in dependencies_include_paths:
161 dependencies_include_paths.append(include_path)
162 165
163 def _resolve_typedefs(self, typed_object): 166 def _resolve_typedefs(self, typed_object):
164 """Resolve typedefs to actual types in the object.""" 167 """Resolve typedefs to actual types in the object."""
165 for attribute_name in typed_object.idl_type_attributes: 168 for attribute_name in typed_object.idl_type_attributes:
166 try: 169 try:
167 idl_type = getattr(typed_object, attribute_name) 170 idl_type = getattr(typed_object, attribute_name)
168 except AttributeError: 171 except AttributeError:
169 continue 172 continue
170 if not idl_type: 173 if not idl_type:
171 continue 174 continue
172 resolved_idl_type = idl_type.resolve_typedefs(self.typedefs) 175 resolved_idl_type = idl_type.resolve_typedefs(self.typedefs)
173 if depends_on_union_types(resolved_idl_type): 176 # TODO(bashi): Dependency resolution shouldn't happen here.
174 self.additional_includes.add( 177 # Move this into includes_for_type() families.
175 self.info_provider.include_path_for_union_types) 178 union_type_name = depending_union_type_name(resolved_idl_type)
179 if union_type_name:
180 self.additional_header_includes.add(
181 self.info_provider.include_path_for_union_types(
182 union_type_name))
176 # Need to re-assign the attribute, not just mutate idl_type, since 183 # Need to re-assign the attribute, not just mutate idl_type, since
177 # type(idl_type) may change. 184 # type(idl_type) may change.
178 setattr(typed_object, attribute_name, resolved_idl_type) 185 setattr(typed_object, attribute_name, resolved_idl_type)
179 186
180 def visit_typed_object(self, typed_object): 187 def visit_typed_object(self, typed_object):
181 self._resolve_typedefs(typed_object) 188 self._resolve_typedefs(typed_object)
182 189
183 190
184 class CodeGeneratorBase(object): 191 class CodeGeneratorBase(object):
185 """Base class for v8 bindings generator and IDL dictionary impl generator""" 192 """Base class for v8 bindings generator and IDL dictionary impl generator"""
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 template_context = interface_context(interface) 265 template_context = interface_context(interface)
259 includes.update(interface_info.get('cpp_includes', {}).get(component, se t())) 266 includes.update(interface_info.get('cpp_includes', {}).get(component, se t()))
260 if not interface.is_partial and not is_testing_target(full_path): 267 if not interface.is_partial and not is_testing_target(full_path):
261 template_context['header_includes'].add(self.info_provider.include_p ath_for_export) 268 template_context['header_includes'].add(self.info_provider.include_p ath_for_export)
262 template_context['exported'] = self.info_provider.specifier_for_expo rt 269 template_context['exported'] = self.info_provider.specifier_for_expo rt
263 # Add the include for interface itself 270 # Add the include for interface itself
264 if IdlType(interface_name).is_typed_array: 271 if IdlType(interface_name).is_typed_array:
265 template_context['header_includes'].add('core/dom/DOMTypedArray.h') 272 template_context['header_includes'].add('core/dom/DOMTypedArray.h')
266 elif interface_info['include_path']: 273 elif interface_info['include_path']:
267 template_context['header_includes'].add(interface_info['include_path ']) 274 template_context['header_includes'].add(interface_info['include_path '])
268 275 template_context['header_includes'].update(
276 interface_info.get('additional_header_includes', []))
269 header_template = self.jinja_env.get_template(header_template_filename) 277 header_template = self.jinja_env.get_template(header_template_filename)
270 cpp_template = self.jinja_env.get_template(cpp_template_filename) 278 cpp_template = self.jinja_env.get_template(cpp_template_filename)
271 header_text, cpp_text = render_template( 279 header_text, cpp_text = render_template(
272 include_paths, header_template, cpp_template, template_context, 280 include_paths, header_template, cpp_template, template_context,
273 component) 281 component)
274 header_path, cpp_path = self.output_paths(interface_name) 282 header_path, cpp_path = self.output_paths(interface_name)
275 return ( 283 return (
276 (header_path, header_text), 284 (header_path, header_text),
277 (cpp_path, cpp_text), 285 (cpp_path, cpp_text),
278 ) 286 )
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 if not definition_name in definitions.dictionaries: 324 if not definition_name in definitions.dictionaries:
317 raise ValueError('%s is not an IDL dictionary') 325 raise ValueError('%s is not an IDL dictionary')
318 interfaces_info = self.info_provider.interfaces_info 326 interfaces_info = self.info_provider.interfaces_info
319 dictionary = definitions.dictionaries[definition_name] 327 dictionary = definitions.dictionaries[definition_name]
320 interface_info = interfaces_info[definition_name] 328 interface_info = interfaces_info[definition_name]
321 header_template = self.jinja_env.get_template('dictionary_impl.h') 329 header_template = self.jinja_env.get_template('dictionary_impl.h')
322 cpp_template = self.jinja_env.get_template('dictionary_impl.cpp') 330 cpp_template = self.jinja_env.get_template('dictionary_impl.cpp')
323 template_context = v8_dictionary.dictionary_impl_context( 331 template_context = v8_dictionary.dictionary_impl_context(
324 dictionary, interfaces_info) 332 dictionary, interfaces_info)
325 include_paths = interface_info.get('dependencies_include_paths') 333 include_paths = interface_info.get('dependencies_include_paths')
326 # Add union containers header file to header_includes rather than
327 # cpp file so that union containers can be used in dictionary headers.
328 union_container_headers = [header for header in include_paths
329 if header.find('UnionTypes') > 0]
330 include_paths = [header for header in include_paths
331 if header not in union_container_headers]
332 template_context['header_includes'].update(union_container_headers)
333 if not is_testing_target(interface_info.get('full_path')): 334 if not is_testing_target(interface_info.get('full_path')):
334 template_context['exported'] = self.info_provider.specifier_for_expo rt 335 template_context['exported'] = self.info_provider.specifier_for_expo rt
335 template_context['header_includes'].add(self.info_provider.include_p ath_for_export) 336 template_context['header_includes'].add(self.info_provider.include_p ath_for_export)
337 template_context['header_includes'].update(
338 interface_info.get('additional_header_includes', []))
336 header_text, cpp_text = render_template( 339 header_text, cpp_text = render_template(
337 include_paths, header_template, cpp_template, template_context) 340 include_paths, header_template, cpp_template, template_context)
338 header_path, cpp_path = self.output_paths( 341 header_path, cpp_path = self.output_paths(
339 cpp_name(dictionary), interface_info) 342 cpp_name(dictionary), interface_info)
340 return ( 343 return (
341 (header_path, header_text), 344 (header_path, header_text),
342 (cpp_path, cpp_text), 345 (cpp_path, cpp_text),
343 ) 346 )
344 347
345 348
346 class CodeGeneratorUnionType(object): 349 class CodeGeneratorUnionType(object):
347 """Generates union type container classes. 350 """Generates union type container classes.
348 This generator is different from CodeGeneratorV8 and 351 This generator is different from CodeGeneratorV8 and
349 CodeGeneratorDictionaryImpl. It assumes that all union types are already 352 CodeGeneratorDictionaryImpl. It assumes that all union types are already
350 collected. It doesn't process idl files directly. 353 collected. It doesn't process idl files directly.
351 """ 354 """
352 def __init__(self, info_provider, cache_dir, output_dir, target_component): 355 def __init__(self, info_provider, cache_dir, output_dir, target_component):
353 self.info_provider = info_provider 356 self.info_provider = info_provider
354 self.jinja_env = initialize_jinja_env(cache_dir) 357 self.jinja_env = initialize_jinja_env(cache_dir)
355 self.output_dir = output_dir 358 self.output_dir = output_dir
356 self.target_component = target_component 359 self.target_component = target_component
357 set_global_type_info(info_provider) 360 set_global_type_info(info_provider)
358 361
359 def generate_code(self): 362 def _generate_container_code(self, union_type):
360 union_types = self.info_provider.union_types 363 header_template = self.jinja_env.get_template('union_container.h')
361 if not union_types: 364 cpp_template = self.jinja_env.get_template('union_container.cpp')
362 return () 365 template_context = v8_union.container_context(
363 header_template = self.jinja_env.get_template('union.h') 366 union_type, self.info_provider.interfaces_info)
364 cpp_template = self.jinja_env.get_template('union.cpp') 367 template_context['header_includes'].append(
365 template_context = v8_union.union_context( 368 self.info_provider.include_path_for_export)
366 union_types, self.info_provider.interfaces_info) 369 template_context['header_includes'] = normalize_and_sort_includes(
370 template_context['header_includes'])
367 template_context['code_generator'] = module_pyname 371 template_context['code_generator'] = module_pyname
368 capitalized_component = self.target_component.capitalize()
369 template_context['exported'] = self.info_provider.specifier_for_export 372 template_context['exported'] = self.info_provider.specifier_for_export
370 template_context['header_filename'] = 'bindings/%s/v8/UnionTypes%s.h' % (
371 self.target_component, capitalized_component)
372 template_context['macro_guard'] = 'UnionType%s_h' % capitalized_componen t
373 additional_header_includes = [self.info_provider.include_path_for_export ]
374
375 # Add UnionTypesCore.h as a dependency when we generate modules union ty pes
376 # because we only generate union type containers which are used by both
377 # core and modules in UnionTypesCore.h.
378 # FIXME: This is an ad hoc workaround and we need a general way to
379 # handle core <-> modules dependency.
380 if self.target_component == 'modules':
381 additional_header_includes.append(
382 'bindings/core/v8/UnionTypesCore.h')
383
384 template_context['header_includes'] = normalize_and_sort_includes(
385 template_context['header_includes'] + additional_header_includes)
386
387 header_text = header_template.render(template_context) 373 header_text = header_template.render(template_context)
388 cpp_text = cpp_template.render(template_context) 374 cpp_text = cpp_template.render(template_context)
389 header_path = posixpath.join(self.output_dir, 375 name = union_type.cpp_type
390 'UnionTypes%s.h' % capitalized_component) 376 header_path = posixpath.join(self.output_dir, '%s.h' % name)
391 cpp_path = posixpath.join(self.output_dir, 377 cpp_path = posixpath.join(self.output_dir, '%s.cpp' % name)
392 'UnionTypes%s.cpp' % capitalized_component)
393 return ( 378 return (
394 (header_path, header_text), 379 (header_path, header_text),
395 (cpp_path, cpp_text), 380 (cpp_path, cpp_text),
396 ) 381 )
397 382
383 def _get_union_types_for_containers(self):
384 union_types = self.info_provider.union_types
385 if not union_types:
386 return None
387 # For container classes we strip nullable wrappers. For example,
388 # both (A or B)? and (A? or B) will become AOrB. This should be OK
389 # because container classes can handle null and it seems that
390 # distinguishing (A or B)? and (A? or B) doesn't make sense.
391 container_cpp_types = set()
392 union_types_for_containers = set()
393 for union_type in union_types:
394 cpp_type = union_type.cpp_type
395 if cpp_type not in container_cpp_types:
396 union_types_for_containers.add(union_type)
397 container_cpp_types.add(cpp_type)
398 return union_types_for_containers
399
400 def generate_code(self):
401 union_types = self._get_union_types_for_containers()
402 if not union_types:
403 return ()
404 outputs = set()
405 for union_type in union_types:
406 outputs.update(self._generate_container_code(union_type))
407 return outputs
408
398 409
399 def initialize_jinja_env(cache_dir): 410 def initialize_jinja_env(cache_dir):
400 jinja_env = jinja2.Environment( 411 jinja_env = jinja2.Environment(
401 loader=jinja2.FileSystemLoader(templates_dir), 412 loader=jinja2.FileSystemLoader(templates_dir),
402 # Bytecode cache is not concurrency-safe unless pre-cached: 413 # Bytecode cache is not concurrency-safe unless pre-cached:
403 # if pre-cached this is read-only, but writing creates a race condition. 414 # if pre-cached this is read-only, but writing creates a race condition.
404 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir), 415 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir),
405 keep_trailing_newline=True, # newline-terminate generated files 416 keep_trailing_newline=True, # newline-terminate generated files
406 lstrip_blocks=True, # so can indent control flow tags 417 lstrip_blocks=True, # so can indent control flow tags
407 trim_blocks=True) 418 trim_blocks=True)
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 467
457 # Create a dummy file as output for the build system, 468 # Create a dummy file as output for the build system,
458 # since filenames of individual cache files are unpredictable and opaque 469 # since filenames of individual cache files are unpredictable and opaque
459 # (they are hashes of the template path, which varies based on environment) 470 # (they are hashes of the template path, which varies based on environment)
460 with open(dummy_filename, 'w') as dummy_file: 471 with open(dummy_filename, 'w') as dummy_file:
461 pass # |open| creates or touches the file 472 pass # |open| creates or touches the file
462 473
463 474
464 if __name__ == '__main__': 475 if __name__ == '__main__':
465 sys.exit(main(sys.argv)) 476 sys.exit(main(sys.argv))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698