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

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

Issue 18341025: Rename deprecated "supplemental_dependencies" and clean up IDL dependency script (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fix exec Created 7 years, 5 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
(Empty)
1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 import optparse
30 import os
31 import os.path
32 import re
33 import string
34
35
36 def parse_options():
37 parser = optparse.OptionParser()
38 parser.add_option('--event-names-file', help='output file')
39 parser.add_option('--idl-files-list', help='file listing all IDLs')
40 parser.add_option('--supplemental-dependency-file', help='output file')
41 parser.add_option('--window-constructors-file', help='output file')
42 parser.add_option('--workerglobalscope-constructors-file', help='output file ')
43 parser.add_option('--sharedworkerglobalscope-constructors-file', help='outpu t file')
44 parser.add_option('--dedicatedworkerglobalscope-constructors-file', help='ou tput file')
45 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')
46 options, args = parser.parse_args()
47 if options.event_names_file is None:
48 parser.error('Must specify an output file using --event-names-file.')
49 if options.supplemental_dependency_file is None:
50 parser.error('Must specify an output file using --supplemental-dependenc y-file.')
51 if options.window_constructors_file is None:
52 parser.error('Must specify an output file using --window-constructors-fi le.')
53 if options.workerglobalscope_constructors_file is None:
54 parser.error('Must specify an output file using --workerglobalscope-cons tructors-file.')
55 if options.workerglobalscope_constructors_file is None:
56 parser.error('Must specify an output file using --sharedworkerglobalscop e-constructors-file.')
57 if options.workerglobalscope_constructors_file is None:
58 parser.error('Must specify an output file using --dedicatedworkerglobals cope-constructors-file.')
59 if options.idl_files_list is None:
60 parser.error('Must specify the file listing all IDLs using --idl-files-l ist.')
61 if options.write_file_only_if_changed is None:
62 parser.error('Must specify whether file is only written if changed using --write-file-only-if-changed.')
63 options.write_file_only_if_changed = bool(options.write_file_only_if_changed )
64 if args:
65 parser.error('No arguments taken, but "%s" given.' % ' '.join(args))
66 return options
67
68
69 def get_file_contents(idl_filename):
70 with open(idl_filename) as idl_file:
71 lines = idl_file.readlines()
72 return ''.join(lines)
73
74
75 def write_file(new_lines, destination_filename, only_if_changed):
76 if only_if_changed and os.path.isfile(destination_filename):
77 with open(destination_filename) as destination_file:
78 old_lines = destination_file.readlines()
79 if old_lines == new_lines:
80 return
81 with open(destination_filename, 'w') as destination_file:
82 destination_file.write(''.join(new_lines))
83
84
85 def get_partial_interface_name_from_idl(file_contents):
86 match = re.search(r'partial\s+interface\s+(\w+)', file_contents)
87 if match:
88 return match.group(1)
89 return None
90
91
92 # identifier-A implements identifier-B;
93 # http://www.w3.org/TR/WebIDL/#idl-implements-statements
94 def get_implemented_interfaces_from_idl(file_contents, interface_name):
95 implemented_interfaces = []
96 for match in re.finditer(r'^\s*(\w+)\s+implements\s+(\w+)\s*;', file_content s, re.MULTILINE):
97 # identifier-A must be the current interface
98 assert match.group(1) == interface_name, \
99 "Identifier on the left of the 'implements' statement should be %s in %s.idl, bu t found %s" % (interface_name, interface_name, match.group(1))
100 implemented_interfaces.append(match.group(2))
101 return implemented_interfaces
102
103 def is_callback_interface_from_idl(file_contents):
104 match = re.search(r'callback\s+interface\s+\w+', file_contents)
105 return match is not None
106
107
108 def get_parent_interface(file_contents):
109 match = re.search(r'interface\s+\w+\s*:\s*(\w+)\s*', file_contents)
110 if match:
111 return match.group(1)
112 return None
113
114 def get_interface_extended_attributes_from_idl(file_contents):
115 extended_attributes = {}
116 match = re.search(r'\[(.*)\]\s+(interface|exception)\s+(\w+)',
117 file_contents, flags=re.DOTALL)
118 if match:
119 parts = string.split(match.group(1), ',')
120 for part in parts:
121 # Match 'key = value'
122 match = re.match(r'([^=\s]*)(?:\s*=\s*(.*))?', part.strip())
123 key = match.group(1)
124 value = match.group(2) or 'VALUE_IS_MISSING'
125 if not key:
126 continue
127 extended_attributes[key] = value
128 return extended_attributes
129
130
131 def generate_constructor_attribute_list(interface_name, extended_attributes):
132 extended_attributes_list = []
133 for attribute_name, attribute_value in extended_attributes.iteritems():
134 if attribute_name not in ['Conditional', 'EnabledAtRuntime', 'EnabledPer Context']:
135 continue
136 extended_attribute = attribute_name
137 if attribute_value != 'VALUE_IS_MISSING':
138 extended_attribute += '=' + attribute_value
139 extended_attributes_list.append(extended_attribute)
140 if extended_attributes_list:
141 extended_string = '[%s] ' % ', '.join(extended_attributes_list)
142 else:
143 extended_string = ''
144
145 attribute_string = 'attribute %(interface_name)sConstructor %(interface_name )s' % {'interface_name': interface_name}
146 attributes_list = [extended_string + attribute_string]
147
148 # In addition to the regular property, for every [NamedConstructor]
149 # extended attribute on an interface, a corresponding property MUST exist
150 # on the ECMAScript global object.
151 if 'NamedConstructor' in extended_attributes:
152 named_constructor = extended_attributes['NamedConstructor']
153 # Extract function name, namely everything before opening '('
154 constructor_name = re.sub(r'\(.*', '', named_constructor)
155 # Note the reduplicated 'ConstructorConstructor'
156 attribute_string = 'attribute %sConstructorConstructor %s' % (interface_ name, constructor_name)
157 attributes_list.append(extended_string + attribute_string)
158
159 return attributes_list
160
161
162 def generate_event_names_file(destination_filename, event_names, only_if_changed =False):
163 source_dir, _ = os.path.split(os.getcwd())
164 lines = []
165 lines.append('namespace="Event"\n')
166 lines.append('\n')
167 for filename in event_names:
168 attributes = []
169 extended_attributes = event_names[filename]
170 for key in ('ImplementedAs', 'Conditional', 'EnabledAtRuntime'):
171 suffix = ''
172 if key == 'EnabledAtRuntime':
173 suffix = 'Enabled'
174 if key in extended_attributes:
175 attributes.append('%s=%s%s' % (key, extended_attributes[key], su ffix))
176 refined_filename, _ = os.path.splitext(os.path.relpath(filename, source_ dir))
177 lines.append('%s %s\n' % (refined_filename, ', '.join(attributes)))
178 write_file(lines, destination_filename, only_if_changed)
179
180
181 def generate_global_constructors_partial_interface(interface_name, destination_f ilename, constructor_attributes_list, only_if_changed=False):
182 lines = []
183 lines.append('partial interface %s {\n' % interface_name)
184 for constructor_attribute in constructor_attributes_list:
185 lines.append(' %s;\n' % constructor_attribute)
186 lines.append('};\n')
187 write_file(lines, destination_filename, only_if_changed)
188
189
190 def parse_idl_files(idl_files, window_constructors_filename, workerglobalscope_c onstructors_filename, sharedworkerglobalscope_constructors_filename, dedicatedwo rkerglobalscope_constructors_filename, event_names_file, only_if_changed=False):
191 interface_name_to_idl_file = {}
192 idl_file_to_interface_name = {}
193 supplemental_dependencies = {}
194 supplementals = {}
195 event_names = {}
196 window_constructor_attributes_list = []
197 workerglobalscope_constructor_attributes_list = []
198 sharedworkerglobalscope_constructor_attributes_list = []
199 dedicatedworkerglobalscope_constructor_attributes_list = []
200
201 parent_interface = {}
202 interface_extended_attribute = {}
203 interface_to_file = {}
204
205 # Populate interface_name_to_idl_file first
206 for idl_file_name in idl_files:
207 full_path = os.path.realpath(idl_file_name)
208 interface_name, _ = os.path.splitext(os.path.basename(idl_file_name))
209 interface_name_to_idl_file[interface_name] = full_path
210
211 for idl_file_name in idl_files:
212 full_path = os.path.realpath(idl_file_name)
213 interface_name, _ = os.path.splitext(os.path.basename(idl_file_name))
214 idl_file_contents = get_file_contents(full_path)
215
216 if interface_name == 'Event':
217 event_names[idl_file_name] = get_interface_extended_attributes_from_ idl(idl_file_contents)
218 else:
219 parent = get_parent_interface(idl_file_contents)
220 if parent:
221 parent_interface[interface_name] = parent
222 interface_extended_attribute[interface_name] = get_interface_ext ended_attributes_from_idl(idl_file_contents)
223 interface_to_file[interface_name] = idl_file_name
224
225 # Handle partial interfaces
226 partial_interface_name = get_partial_interface_name_from_idl(idl_file_co ntents)
227 if partial_interface_name:
228 supplemental_dependencies[full_path] = [partial_interface_name]
229 continue
230
231 # Parse 'identifier-A implements identifier-B; statements
232 implemented_interfaces = get_implemented_interfaces_from_idl(idl_file_co ntents, interface_name)
233 for implemented_interface in implemented_interfaces:
234 assert implemented_interface in interface_name_to_idl_file, \
235 "Could not find a the IDL file where the following implemented interface is defi ned: %s" % implemented_interface
236 supplemental_dependencies.setdefault(interface_name_to_idl_file[impl emented_interface], []).append(interface_name)
237 # Handle [NoInterfaceObject]
238 if not is_callback_interface_from_idl(idl_file_contents):
239 extended_attributes = get_interface_extended_attributes_from_idl(idl _file_contents)
240 if 'NoInterfaceObject' not in extended_attributes:
241 global_contexts = extended_attributes.get('GlobalContext', 'Wind ow').split('&')
242 constructor_list = generate_constructor_attribute_list(interface _name, extended_attributes)
243 if 'Window' in global_contexts:
244 window_constructor_attributes_list.extend(constructor_list)
245 if 'WorkerGlobalScope' in global_contexts:
246 workerglobalscope_constructor_attributes_list.extend(constru ctor_list)
247 if 'SharedWorkerGlobalScope' in global_contexts:
248 sharedworkerglobalscope_constructor_attributes_list.extend(c onstructor_list)
249 if 'DedicatedWorkerGlobalScope' in global_contexts:
250 dedicatedworkerglobalscope_constructor_attributes_list.exten d(constructor_list)
251 idl_file_to_interface_name[full_path] = interface_name
252 supplementals[full_path] = []
253
254 for interface in parent_interface:
255 parent = parent_interface[interface]
256 while parent in parent_interface:
257 parent = parent_interface[parent]
258 if parent == 'Event':
259 event_names[interface_to_file[interface]] = interface_extended_attri bute[interface]
260 generate_event_names_file(event_names_file, event_names, only_if_changed=onl y_if_changed)
261
262 # Generate Global constructors
263 if 'Window' in interface_name_to_idl_file:
264 generate_global_constructors_partial_interface("Window", window_construc tors_filename, window_constructor_attributes_list, only_if_changed=only_if_chang ed)
265 supplemental_dependencies[window_constructors_filename] = ['Window']
266 if 'WorkerGlobalScope' in interface_name_to_idl_file:
267 generate_global_constructors_partial_interface("WorkerGlobalScope", work erglobalscope_constructors_filename, workerglobalscope_constructor_attributes_li st, only_if_changed=only_if_changed)
268 supplemental_dependencies[workerglobalscope_constructors_filename] = ['W orkerGlobalScope']
269 if 'SharedWorkerGlobalScope' in interface_name_to_idl_file:
270 generate_global_constructors_partial_interface("SharedWorkerGlobalScope" , sharedworkerglobalscope_constructors_filename, sharedworkerglobalscope_constru ctor_attributes_list, only_if_changed=only_if_changed)
271 supplemental_dependencies[sharedworkerglobalscope_constructors_filename] = ['SharedWorkerGlobalScope']
272 if 'DedicatedWorkerGlobalScope' in interface_name_to_idl_file:
273 generate_global_constructors_partial_interface("DedicatedWorkerGlobalSco pe", dedicatedworkerglobalscope_constructors_filename, dedicatedworkerglobalscop e_constructor_attributes_list, only_if_changed=only_if_changed)
274 supplemental_dependencies[dedicatedworkerglobalscope_constructors_filena me] = ['DedicatedWorkerGlobalScope']
275
276 # Resolve partial interfaces dependencies
277 for idl_file, base_files in supplemental_dependencies.iteritems():
278 for base_file in base_files:
279 target_idl_file = interface_name_to_idl_file[base_file]
280 supplementals[target_idl_file].append(idl_file)
281 if idl_file in supplementals:
282 # Should never occur. Might be needed in corner cases.
283 del supplementals[idl_file]
284 return supplementals
285
286
287 def write_dependency_file(filename, supplementals, only_if_changed=False):
288 """Outputs the dependency file.
289
290 The format of a supplemental dependency file:
291
292 Window.idl P.idl Q.idl R.idl
293 Document.idl S.idl
294 Event.idl
295 ...
296
297 The above indicates that:
298 Window.idl is supplemented by P.idl, Q.idl and R.idl,
299 Document.idl is supplemented by S.idl, and
300 Event.idl is supplemented by no IDLs.
301
302 An IDL that supplements another IDL (e.g. P.idl) does not have its own
303 lines in the dependency file.
304 """
305 lines = []
306 for idl_file, supplemental_files in sorted(supplementals.iteritems()):
307 lines.append('%s %s\n' % (idl_file, ' '.join(supplemental_files)))
308 write_file(lines, filename, only_if_changed)
309
310
311 def main():
312 options = parse_options()
313 idl_files = []
314 with open(options.idl_files_list) as idl_files_list_file:
315 for line in idl_files_list_file:
316 idl_files.append(string.rstrip(line, '\n'))
317 resolved_supplementals = parse_idl_files(idl_files, options.window_construct ors_file, options.workerglobalscope_constructors_file, options.sharedworkergloba lscope_constructors_file, options.dedicatedworkerglobalscope_constructors_file, options.event_names_file, only_if_changed=options.write_file_only_if_changed)
318 write_dependency_file(options.supplemental_dependency_file, resolved_supplem entals, only_if_changed=options.write_file_only_if_changed)
319
320
321 if __name__ == '__main__':
322 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698