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

Side by Side Diff: Source/bindings/scripts/generate_global_constructors.py

Issue 261243002: Add support for [Global] / [PrimaryGlobal] IDL extended attributes (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fix nit Created 6 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 | Annotate | Revision Log
« no previous file with comments | « Source/bindings/generated_bindings.gyp ('k') | Source/bindings/scripts/utilities.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # 2 #
3 # Copyright 2014 The Chromium Authors. All rights reserved. 3 # Copyright 2014 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Generates interface properties on global objects. 7 """Generates interface properties on global objects.
8 8
9 Concretely these are implemented as "constructor attributes", meaning 9 Concretely these are implemented as "constructor attributes", meaning
10 "attributes whose name ends with Constructor" (special-cased by code generator), 10 "attributes whose name ends with Constructor" (special-cased by code generator),
11 hence "global constructors" for short. 11 hence "global constructors" for short.
12 12
13 For reference on global objects, see: 13 For reference on global objects, see:
14 http://heycam.github.io/webidl/#Global 14 http://heycam.github.io/webidl/#Global
15 http://heycam.github.io/webidl/#Exposed 15 http://heycam.github.io/webidl/#Exposed
16 16
17 Design document: http://www.chromium.org/developers/design-documents/idl-build 17 Design document: http://www.chromium.org/developers/design-documents/idl-build
18 """ 18 """
19 19
20 import itertools
20 import optparse 21 import optparse
21 import os 22 import os
22 import re 23 import re
23 import sys 24 import sys
24 25
26 from collections import defaultdict
25 from utilities import get_file_contents, write_file, get_interface_extended_attr ibutes_from_idl, is_callback_interface_from_idl 27 from utilities import get_file_contents, write_file, get_interface_extended_attr ibutes_from_idl, is_callback_interface_from_idl
26 28
27 global_objects = {} 29 interface_name_to_global_names = defaultdict(list)
30 global_name_to_constructors = defaultdict(list)
28 31
29 32
30 HEADER_FORMAT = """ 33 HEADER_FORMAT = """
31 // Stub header file for {{idl_basename}} 34 // Stub header file for {{idl_basename}}
32 // Required because the IDL compiler assumes that a corresponding header file 35 // Required because the IDL compiler assumes that a corresponding header file
33 // exists for each IDL file. 36 // exists for each IDL file.
34 """ 37 """
35 38
36 def parse_options(): 39 def parse_options():
37 parser = optparse.OptionParser() 40 parser = optparse.OptionParser()
38 parser.add_option('--idl-files-list', help='file listing IDL files') 41 parser.add_option('--idl-files-list', help='file listing IDL files')
39 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') 42 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')
40 43
41 options, args = parser.parse_args() 44 options, args = parser.parse_args()
42 45
43 if options.idl_files_list is None: 46 if options.idl_files_list is None:
44 parser.error('Must specify a file listing IDL files using --idl-files-li st.') 47 parser.error('Must specify a file listing IDL files using --idl-files-li st.')
45 if options.write_file_only_if_changed is None: 48 if options.write_file_only_if_changed is None:
46 parser.error('Must specify whether output files are only written if chan ged using --write-file-only-if-changed.') 49 parser.error('Must specify whether output files are only written if chan ged using --write-file-only-if-changed.')
47 options.write_file_only_if_changed = bool(options.write_file_only_if_changed ) 50 options.write_file_only_if_changed = bool(options.write_file_only_if_changed )
48 51
49 return options, args 52 return options, args
50 53
51 54
52 # Global name: http://heycam.github.io/webidl/#dfn-global-name 55 def interface_to_global_names(interface_name, extended_attributes):
53 # FIXME: We should add support for [Global=xx] extended attribute instead of 56 """Returns global names, if any, for an interface name.
54 # hard-coding this mapping. 57
55 def global_name_to_interface_name(global_name): 58 If the [Global] or [PrimaryGlobal] extended attribute is declared with an
56 if global_name.endswith('Worker'): 59 identifier list argument, then those identifiers are the interface's global
57 return global_name + 'GlobalScope' 60 names; otherwise, the interface has a single global name, which is the
58 return global_name 61 interface's identifier (http://heycam.github.io/webidl/#Global).
62 """
63 for key in ['Global', 'PrimaryGlobal']:
64 if key not in extended_attributes:
65 continue
66 global_value = extended_attributes[key]
67 if global_value:
68 # FIXME: In spec names are comma-separated, but that makes parsing v ery
69 # difficult (https://www.w3.org/Bugs/Public/show_bug.cgi?id=24959).
70 return global_value.split('&')
71 return [interface_name]
72 return []
73
74
75 def flatten_list(iterable):
76 return list(itertools.chain.from_iterable(iterable))
77
78
79 def interface_name_to_constructors(interface_name):
80 """Returns constructors for an interface."""
81 global_names = interface_name_to_global_names[interface_name]
82 return flatten_list(global_name_to_constructors[global_name]
83 for global_name in global_names)
59 84
60 85
61 def record_global_constructors(idl_filename): 86 def record_global_constructors(idl_filename):
62 interface_name, _ = os.path.splitext(os.path.basename(idl_filename)) 87 interface_name, _ = os.path.splitext(os.path.basename(idl_filename))
63 full_path = os.path.realpath(idl_filename) 88 full_path = os.path.realpath(idl_filename)
64 idl_file_contents = get_file_contents(full_path) 89 idl_file_contents = get_file_contents(full_path)
65 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents) 90 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents)
66 91
67 # An interface property is produced for every non-callback interface 92 # An interface property is produced for every non-callback interface
68 # that does not have [NoInterfaceObject]. 93 # that does not have [NoInterfaceObject].
69 # Callback interfaces with constants also have interface properties, 94 # Callback interfaces with constants also have interface properties,
70 # but there are none of these in Blink. 95 # but there are none of these in Blink.
71 # http://heycam.github.io/webidl/#es-interfaces 96 # http://heycam.github.io/webidl/#es-interfaces
72 if (is_callback_interface_from_idl(idl_file_contents) or 97 if (is_callback_interface_from_idl(idl_file_contents) or
73 'NoInterfaceObject' in extended_attributes): 98 'NoInterfaceObject' in extended_attributes):
74 return 99 return
75 100
101 # Check if interface has [Global] / [PrimaryGlobal] extended attributes.
102 interface_name_to_global_names[interface_name] = interface_to_global_names(i nterface_name, extended_attributes)
103
104 # The [Exposed] extended attribute MUST take an identifier list. Each
105 # identifier in the list MUST be a global name. An interface or interface
106 # member the extended attribute applies to will be exposed only on objects
107 # associated with ECMAScript global environments whose global object
108 # implements an interface that has a matching global name.
76 # FIXME: In spec names are comma-separated, but that makes parsing very 109 # FIXME: In spec names are comma-separated, but that makes parsing very
77 # difficult (https://www.w3.org/Bugs/Public/show_bug.cgi?id=24959). 110 # difficult (https://www.w3.org/Bugs/Public/show_bug.cgi?id=24959).
78 global_names = extended_attributes.get('Exposed', 'Window').split('&') 111 exposed_global_names = extended_attributes.get('Exposed', 'Window').split('& ')
79 new_constructors_list = generate_global_constructors_list(interface_name, ex tended_attributes) 112 new_constructors_list = generate_global_constructors_list(interface_name, ex tended_attributes)
80 for global_name in global_names: 113 for exposed_global_name in exposed_global_names:
81 interface_name = global_name_to_interface_name(global_name) 114 global_name_to_constructors[exposed_global_name].extend(new_constructors _list)
82 global_objects[interface_name]['constructors'].extend(new_constructors_l ist)
83 115
84 116
85 def generate_global_constructors_list(interface_name, extended_attributes): 117 def generate_global_constructors_list(interface_name, extended_attributes):
86 extended_attributes_list = [ 118 extended_attributes_list = [
87 name + '=' + extended_attributes[name] 119 name + '=' + extended_attributes[name]
88 for name in 'Conditional', 'PerContextEnabled', 'RuntimeEnabled' 120 for name in 'Conditional', 'PerContextEnabled', 'RuntimeEnabled'
89 if name in extended_attributes] 121 if name in extended_attributes]
90 if extended_attributes_list: 122 if extended_attributes_list:
91 extended_string = '[%s] ' % ', '.join(extended_attributes_list) 123 extended_string = '[%s] ' % ', '.join(extended_attributes_list)
92 else: 124 else:
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 # limits. This is generated at GYP time, which is ok b/c files are static. 166 # limits. This is generated at GYP time, which is ok b/c files are static.
135 with open(options.idl_files_list) as idl_files_list: 167 with open(options.idl_files_list) as idl_files_list:
136 idl_files = [line.rstrip('\n') for line in idl_files_list] 168 idl_files = [line.rstrip('\n') for line in idl_files_list]
137 169
138 # Output IDL files (to generate) are passed at the command line, since 170 # Output IDL files (to generate) are passed at the command line, since
139 # these are in the build directory, which is determined at build time, not 171 # these are in the build directory, which is determined at build time, not
140 # GYP time. 172 # GYP time.
141 # These are passed as pairs of GlobalObjectName, GlobalObject.idl 173 # These are passed as pairs of GlobalObjectName, GlobalObject.idl
142 interface_name_idl_filename = [(args[i], args[i + 1]) 174 interface_name_idl_filename = [(args[i], args[i + 1])
143 for i in range(0, len(args), 2)] 175 for i in range(0, len(args), 2)]
144 global_objects.update(
145 (interface_name, {
146 'idl_filename': idl_filename,
147 'constructors': [],
148 })
149 for interface_name, idl_filename in interface_name_idl_filename)
150 176
151 for idl_filename in idl_files: 177 for idl_filename in idl_files:
152 record_global_constructors(idl_filename) 178 record_global_constructors(idl_filename)
153 179
154 for interface_name, global_object in global_objects.iteritems(): 180 # Check for [Exposed] / [Global] mismatch.
181 known_global_names = set(itertools.chain.from_iterable(interface_name_to_glo bal_names.values()))
182 unknown_global_names = set(global_name_to_constructors).difference(known_glo bal_names)
183 if unknown_global_names:
184 raise ValueError('The following global names were used in '
185 '[Exposed=xxx] but do not match any [Global] / '
186 '[PrimaryGlobal] interface: %s'
187 % list(unknown_global_names))
188
189 # Write partial interfaces containing constructor attributes for each
190 # global interface.
191 for interface_name, idl_filename in interface_name_idl_filename:
192 constructors = interface_name_to_constructors(interface_name)
155 write_global_constructors_partial_interface( 193 write_global_constructors_partial_interface(
156 interface_name, 194 interface_name,
157 global_object['idl_filename'], 195 idl_filename,
158 global_object['constructors'], 196 constructors,
159 options.write_file_only_if_changed) 197 options.write_file_only_if_changed)
160 198
161 199
162 if __name__ == '__main__': 200 if __name__ == '__main__':
163 sys.exit(main()) 201 sys.exit(main())
OLDNEW
« no previous file with comments | « Source/bindings/generated_bindings.gyp ('k') | Source/bindings/scripts/utilities.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698