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

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: Remove non-ASCII character in comment 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
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 optparse 20 import optparse
21 import os 21 import os
22 import re 22 import re
23 import sys 23 import sys
24 24
25 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 26 from utilities import get_file_contents, write_file, get_interface_extended_attr ibutes_from_idl, is_callback_interface_from_idl
26 27
27 global_objects = {} 28 global_name_to_interface_names = defaultdict(list)
29 global_name_to_constructors = defaultdict(list)
28 30
29 31
30 HEADER_FORMAT = """ 32 HEADER_FORMAT = """
31 // Stub header file for {{idl_basename}} 33 // Stub header file for {{idl_basename}}
32 // Required because the IDL compiler assumes that a corresponding header file 34 // Required because the IDL compiler assumes that a corresponding header file
33 // exists for each IDL file. 35 // exists for each IDL file.
34 """ 36 """
35 37
36 def parse_options(): 38 def parse_options():
37 parser = optparse.OptionParser() 39 parser = optparse.OptionParser()
38 parser.add_option('--idl-files-list', help='file listing IDL files') 40 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') 41 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 42
41 options, args = parser.parse_args() 43 options, args = parser.parse_args()
42 44
43 if options.idl_files_list is None: 45 if options.idl_files_list is None:
44 parser.error('Must specify a file listing IDL files using --idl-files-li st.') 46 parser.error('Must specify a file listing IDL files using --idl-files-li st.')
45 if options.write_file_only_if_changed is None: 47 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.') 48 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 ) 49 options.write_file_only_if_changed = bool(options.write_file_only_if_changed )
48 50
49 return options, args 51 return options, args
50 52
51 53
52 # Global name: http://heycam.github.io/webidl/#dfn-global-name 54 # If the [Global] or [PrimaryGlobal] extended attribute is declared with an
Nils Barth (inactive) 2014/05/07 01:55:57 Could you put this explanation in a docstring inst
Inactive 2014/05/07 15:45:12 Done.
53 # FIXME: We should add support for [Global=xx] extended attribute instead of 55 # identifier list argument, then those identifiers are the interface's global
54 # hard-coding this mapping. 56 # names; otherwise, the interface has a single global name, which is the
55 def global_name_to_interface_name(global_name): 57 # interface's identifier.
56 if global_name.endswith('Worker'): 58 # http://heycam.github.io/webidl/#Global
57 return global_name + 'GlobalScope' 59 def interface_to_global_names(interface_name, extended_attributes):
58 return global_name 60 for extended_attribute in ['Global', 'PrimaryGlobal']:
Nils Barth (inactive) 2014/05/07 01:55:57 |key| is fine for the name here
Inactive 2014/05/07 15:45:12 Done.
61 global_value = extended_attributes.get(extended_attribute)
Nils Barth (inactive) 2014/05/07 01:55:57 Could you flatten this logic? I generally prefer
Inactive 2014/05/07 15:45:12 Done.
62 if global_value is not None:
63 if len(global_value) > 0:
64 # FIXME: In spec names are comma-separated, but that makes parsi ng very
65 # difficult (https://www.w3.org/Bugs/Public/show_bug.cgi?id=2495 9).
66 return global_value.split('&')
67 else:
68 return [interface_name]
69 return []
59 70
60 71
61 def record_global_constructors(idl_filename): 72 def record_global_constructors(idl_filename):
62 interface_name, _ = os.path.splitext(os.path.basename(idl_filename)) 73 interface_name, _ = os.path.splitext(os.path.basename(idl_filename))
63 full_path = os.path.realpath(idl_filename) 74 full_path = os.path.realpath(idl_filename)
64 idl_file_contents = get_file_contents(full_path) 75 idl_file_contents = get_file_contents(full_path)
65 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents) 76 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents)
66 77
67 # An interface property is produced for every non-callback interface 78 # An interface property is produced for every non-callback interface
68 # that does not have [NoInterfaceObject]. 79 # that does not have [NoInterfaceObject].
69 # Callback interfaces with constants also have interface properties, 80 # Callback interfaces with constants also have interface properties,
70 # but there are none of these in Blink. 81 # but there are none of these in Blink.
71 # http://heycam.github.io/webidl/#es-interfaces 82 # http://heycam.github.io/webidl/#es-interfaces
72 if (is_callback_interface_from_idl(idl_file_contents) or 83 if (is_callback_interface_from_idl(idl_file_contents) or
73 'NoInterfaceObject' in extended_attributes): 84 'NoInterfaceObject' in extended_attributes):
74 return 85 return
75 86
87 # Check if interface has [Global] / [PrimaryGlobal] extended attributes.
88 global_names = interface_to_global_names(interface_name, extended_attributes )
89 for global_name in global_names:
90 global_name_to_interface_names[global_name].append(interface_name)
91
92 # The [Exposed] extended attribute MUST take an identifier list. Each
93 # identifier in the list MUST be a global name. An interface or interface
94 # member the extended attribute applies to will be exposed only on objects
95 # associated with ECMAScript global environments whose global object
96 # implements an interface that has a matching global name.
76 # FIXME: In spec names are comma-separated, but that makes parsing very 97 # 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). 98 # difficult (https://www.w3.org/Bugs/Public/show_bug.cgi?id=24959).
78 global_names = extended_attributes.get('Exposed', 'Window').split('&') 99 exposed_global_names = extended_attributes.get('Exposed', 'Window').split('& ')
79 new_constructors_list = generate_global_constructors_list(interface_name, ex tended_attributes) 100 new_constructors_list = generate_global_constructors_list(interface_name, ex tended_attributes)
80 for global_name in global_names: 101 for exposed_global_name in exposed_global_names:
81 interface_name = global_name_to_interface_name(global_name) 102 global_name_to_constructors[exposed_global_name].extend(new_constructors _list)
82 global_objects[interface_name]['constructors'].extend(new_constructors_l ist)
83 103
84 104
85 def generate_global_constructors_list(interface_name, extended_attributes): 105 def generate_global_constructors_list(interface_name, extended_attributes):
86 extended_attributes_list = [ 106 extended_attributes_list = [
87 name + '=' + extended_attributes[name] 107 name + '=' + extended_attributes[name]
88 for name in 'Conditional', 'PerContextEnabled', 'RuntimeEnabled' 108 for name in 'Conditional', 'PerContextEnabled', 'RuntimeEnabled'
89 if name in extended_attributes] 109 if name in extended_attributes]
90 if extended_attributes_list: 110 if extended_attributes_list:
91 extended_string = '[%s] ' % ', '.join(extended_attributes_list) 111 extended_string = '[%s] ' % ', '.join(extended_attributes_list)
92 else: 112 else:
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 152
133 # Input IDL files are passed in a file, due to OS command line length 153 # Input IDL files are passed in a file, due to OS command line length
134 # limits. This is generated at GYP time, which is ok b/c files are static. 154 # 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: 155 with open(options.idl_files_list) as idl_files_list:
136 idl_files = [line.rstrip('\n') for line in idl_files_list] 156 idl_files = [line.rstrip('\n') for line in idl_files_list]
137 157
138 # Output IDL files (to generate) are passed at the command line, since 158 # 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 159 # these are in the build directory, which is determined at build time, not
140 # GYP time. 160 # GYP time.
141 # These are passed as pairs of GlobalObjectName, GlobalObject.idl 161 # These are passed as pairs of GlobalObjectName, GlobalObject.idl
142 interface_name_idl_filename = [(args[i], args[i + 1]) 162 interface_name_to_idl_filename = {args[i]: args[i + 1]
Nils Barth (inactive) 2014/05/07 01:55:57 Need to use dict(...) instead of {...: ...}: dicti
Inactive 2014/05/07 15:45:12 Done.
143 for i in range(0, len(args), 2)] 163 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 164
151 for idl_filename in idl_files: 165 for idl_filename in idl_files:
152 record_global_constructors(idl_filename) 166 record_global_constructors(idl_filename)
153 167
154 for interface_name, global_object in global_objects.iteritems(): 168 # An interface can have multiple global names (e.g.
Nils Barth (inactive) 2014/05/07 01:55:57 This is really confusing; I think it's because of
Inactive 2014/05/07 15:45:12 Done.
169 # Global=Worker&SharedWorker) so we construct a
170 # interface_name_to_constructors dict from global_name_to_constructors and
171 # global_name_to_interface_names.
172 interface_name_to_constructors = defaultdict(list)
173 for global_name, constructors in global_name_to_constructors.iteritems():
174 assert global_name in global_name_to_interface_names, \
Nils Barth (inactive) 2014/05/07 01:55:57 This assert is not needed, since it'll trigger an
Inactive 2014/05/07 15:45:12 Done.
175 'Unknown global name: "%s", values in [Exposed=xx] must '\
176 'correspond to a [Global] or [PrimaryGlobal] extended '\
177 'attribute.' % global_name
178 for interface_name in global_name_to_interface_names[global_name]:
179 interface_name_to_constructors[interface_name].extend(constructors)
180
181 # Write partial interfaces containing constructor attributes for each
182 # global interface.
183 for interface_name, constructors in interface_name_to_constructors.iteritems ():
Nils Barth (inactive) 2014/05/07 01:55:57 for interface_name, idl_filename in interface_name
Inactive 2014/05/07 15:45:12 Done.
155 write_global_constructors_partial_interface( 184 write_global_constructors_partial_interface(
156 interface_name, 185 interface_name,
157 global_object['idl_filename'], 186 interface_name_to_idl_filename[interface_name],
Nils Barth (inactive) 2014/05/07 01:55:57 How about: interface_name, idl_filename, interface
Inactive 2014/05/07 15:45:12 Done.
158 global_object['constructors'], 187 constructors,
159 options.write_file_only_if_changed) 188 options.write_file_only_if_changed)
160 189
161 190
162 if __name__ == '__main__': 191 if __name__ == '__main__':
163 sys.exit(main()) 192 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698