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

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

Issue 309793002: IDL build: Split global objects computation from global constructors computation (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Tweak Created 6 years, 6 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
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 itertools
21 import optparse 21 import optparse
22 import os 22 import os
23 import cPickle as pickle
23 import re 24 import re
24 import sys 25 import sys
25 26
26 from collections import defaultdict 27 from collections import defaultdict
27 from utilities import get_file_contents, write_file, get_interface_extended_attr ibutes_from_idl, is_callback_interface_from_idl 28 from utilities import get_file_contents, idl_filename_to_interface_name, read_fi le_to_list, write_file, get_interface_extended_attributes_from_idl, is_callback_ interface_from_idl
28 29
29 interface_name_to_global_names = defaultdict(list) 30 interface_name_to_global_names = {}
30 global_name_to_constructors = defaultdict(list) 31 global_name_to_constructors = defaultdict(list)
31 32
32 33
33 HEADER_FORMAT = """ 34 HEADER_FORMAT = """// Stub header file for {{idl_basename}}
34 // Stub header file for {{idl_basename}}
35 // Required because the IDL compiler assumes that a corresponding header file 35 // Required because the IDL compiler assumes that a corresponding header file
36 // exists for each IDL file. 36 // exists for each IDL file.
37 """ 37 """
38 38
39 def parse_options(): 39 def parse_options():
40 parser = optparse.OptionParser() 40 parser = optparse.OptionParser()
41 parser.add_option('--idl-files-list', help='file listing IDL files') 41 parser.add_option('--idl-files-list', help='file listing IDL files')
42 parser.add_option('--global-objects-file', help='pickle file of global objec ts')
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') 43 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')
43 44
44 options, args = parser.parse_args() 45 options, args = parser.parse_args()
45 46
46 if options.idl_files_list is None: 47 if options.idl_files_list is None:
47 parser.error('Must specify a file listing IDL files using --idl-files-li st.') 48 parser.error('Must specify a file listing IDL files using --idl-files-li st.')
49 if options.global_objects_file is None:
50 parser.error('Must specify a pickle file of global objects using --globa l-objects-file.')
48 if options.write_file_only_if_changed is None: 51 if options.write_file_only_if_changed is None:
49 parser.error('Must specify whether output files are only written if chan ged using --write-file-only-if-changed.') 52 parser.error('Must specify whether output files are only written if chan ged using --write-file-only-if-changed.')
50 options.write_file_only_if_changed = bool(options.write_file_only_if_changed ) 53 options.write_file_only_if_changed = bool(options.write_file_only_if_changed )
51 54
52 return options, args 55 return options, args
53 56
54 57
55 def interface_to_global_names(interface_name, extended_attributes):
56 """Returns global names, if any, for an interface name.
57
58 If the [Global] or [PrimaryGlobal] extended attribute is declared with an
59 identifier list argument, then those identifiers are the interface's global
60 names; otherwise, the interface has a single global name, which is the
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): 58 def flatten_list(iterable):
76 return list(itertools.chain.from_iterable(iterable)) 59 return list(itertools.chain.from_iterable(iterable))
77 60
78 61
79 def interface_name_to_constructors(interface_name): 62 def interface_name_to_constructors(interface_name):
80 """Returns constructors for an interface.""" 63 """Returns constructors for an interface."""
81 global_names = interface_name_to_global_names[interface_name] 64 global_names = interface_name_to_global_names[interface_name]
82 return flatten_list(global_name_to_constructors[global_name] 65 return flatten_list(global_name_to_constructors[global_name]
83 for global_name in global_names) 66 for global_name in global_names)
84 67
85 68
86 def record_global_constructors(idl_filename): 69 def record_global_constructors(idl_filename):
87 interface_name, _ = os.path.splitext(os.path.basename(idl_filename)) 70 interface_name = idl_filename_to_interface_name(idl_filename)
88 full_path = os.path.realpath(idl_filename) 71 full_path = os.path.realpath(idl_filename)
89 idl_file_contents = get_file_contents(full_path) 72 idl_file_contents = get_file_contents(full_path)
90 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents) 73 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents)
91 74
92 # An interface property is produced for every non-callback interface 75 # An interface property is produced for every non-callback interface
93 # that does not have [NoInterfaceObject]. 76 # that does not have [NoInterfaceObject].
94 # Callback interfaces with constants also have interface properties, 77 # Callback interfaces with constants also have interface properties,
95 # but there are none of these in Blink. 78 # but there are none of these in Blink.
96 # http://heycam.github.io/webidl/#es-interfaces 79 # http://heycam.github.io/webidl/#es-interfaces
97 if (is_callback_interface_from_idl(idl_file_contents) or 80 if (is_callback_interface_from_idl(idl_file_contents) or
98 'NoInterfaceObject' in extended_attributes): 81 'NoInterfaceObject' in extended_attributes):
99 return 82 return
100 83
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 84 # The [Exposed] extended attribute MUST take an identifier list. Each
105 # identifier in the list MUST be a global name. An interface or interface 85 # 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 86 # member the extended attribute applies to will be exposed only on objects
107 # associated with ECMAScript global environments whose global object 87 # associated with ECMAScript global environments whose global object
108 # implements an interface that has a matching global name. 88 # implements an interface that has a matching global name.
109 # FIXME: In spec names are comma-separated, but that makes parsing very 89 # FIXME: In spec names are comma-separated, but that makes parsing very
110 # difficult (https://www.w3.org/Bugs/Public/show_bug.cgi?id=24959). 90 # difficult (https://www.w3.org/Bugs/Public/show_bug.cgi?id=24959).
111 exposed_global_names = extended_attributes.get('Exposed', 'Window').split('& ') 91 exposed_global_names = extended_attributes.get('Exposed', 'Window').split('& ')
112 new_constructors_list = generate_global_constructors_list(interface_name, ex tended_attributes) 92 new_constructors_list = generate_global_constructors_list(interface_name, ex tended_attributes)
113 for exposed_global_name in exposed_global_names: 93 for exposed_global_name in exposed_global_names:
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 header_filename, only_if_changed) 137 header_filename, only_if_changed)
158 138
159 139
160 ################################################################################ 140 ################################################################################
161 141
162 def main(): 142 def main():
163 options, args = parse_options() 143 options, args = parse_options()
164 144
165 # Input IDL files are passed in a file, due to OS command line length 145 # Input IDL files are passed in a file, due to OS command line length
166 # limits. This is generated at GYP time, which is ok b/c files are static. 146 # limits. This is generated at GYP time, which is ok b/c files are static.
167 with open(options.idl_files_list) as idl_files_list: 147 idl_files = read_file_to_list(options.idl_files_list)
168 idl_files = [line.rstrip('\n') for line in idl_files_list]
169 148
170 # Output IDL files (to generate) are passed at the command line, since 149 # Output IDL files (to generate) are passed at the command line, since
171 # these are in the build directory, which is determined at build time, not 150 # these are in the build directory, which is determined at build time, not
172 # GYP time. 151 # GYP time.
173 # These are passed as pairs of GlobalObjectName, GlobalObject.idl 152 # These are passed as pairs of GlobalObjectName, GlobalObject.idl
174 interface_name_idl_filename = [(args[i], args[i + 1]) 153 interface_name_idl_filename = [(args[i], args[i + 1])
175 for i in range(0, len(args), 2)] 154 for i in range(0, len(args), 2)]
176 155
156 with open(options.global_objects_file) as global_objects_file:
157 interface_name_to_global_names.update(pickle.load(global_objects_file))
158
177 for idl_filename in idl_files: 159 for idl_filename in idl_files:
178 record_global_constructors(idl_filename) 160 record_global_constructors(idl_filename)
179 161
180 # Check for [Exposed] / [Global] mismatch. 162 # Check for [Exposed] / [Global] mismatch.
181 known_global_names = set(itertools.chain.from_iterable(interface_name_to_glo bal_names.values())) 163 known_global_names = frozenset(itertools.chain.from_iterable(interface_name_ to_global_names.values()))
182 unknown_global_names = set(global_name_to_constructors).difference(known_glo bal_names) 164 exposed_global_names = frozenset(global_name_to_constructors)
183 if unknown_global_names: 165 if not exposed_global_names.issubset(known_global_names):
166 unknown_global_names = exposed_global_names.difference(known_global_name s)
184 raise ValueError('The following global names were used in ' 167 raise ValueError('The following global names were used in '
185 '[Exposed=xxx] but do not match any [Global] / ' 168 '[Exposed=xxx] but do not match any [Global] / '
186 '[PrimaryGlobal] interface: %s' 169 '[PrimaryGlobal] interface: %s'
187 % list(unknown_global_names)) 170 % list(unknown_global_names))
188 171
189 # Write partial interfaces containing constructor attributes for each 172 # Write partial interfaces containing constructor attributes for each
190 # global interface. 173 # global interface.
191 for interface_name, idl_filename in interface_name_idl_filename: 174 for interface_name, idl_filename in interface_name_idl_filename:
192 constructors = interface_name_to_constructors(interface_name) 175 constructors = interface_name_to_constructors(interface_name)
193 write_global_constructors_partial_interface( 176 write_global_constructors_partial_interface(
194 interface_name, 177 interface_name,
195 idl_filename, 178 idl_filename,
196 constructors, 179 constructors,
197 options.write_file_only_if_changed) 180 options.write_file_only_if_changed)
198 181
199 182
200 if __name__ == '__main__': 183 if __name__ == '__main__':
201 sys.exit(main()) 184 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698