OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
3 # for details. All rights reserved. Use of this source code is governed by a | 3 # for details. All rights reserved. Use of this source code is governed by a |
4 # BSD-style license that can be found in the LICENSE file. | 4 # BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 """This module provides shared functionality for the system to generate | 6 """This module provides shared functionality for the system to generate |
7 dart:html APIs from the IDL database.""" | 7 dart:html APIs from the IDL database.""" |
8 | 8 |
9 from generator import DartDomNameOfAttribute | 9 from generator import AnalyzeOperation, ConstantOutputOrder, \ |
10 DartDomNameOfAttribute, FindMatchingAttribute, IsDartCollectionType, \ | |
11 IsPureInterface | |
12 | |
13 # Types that are accessible cross-frame in a limited fashion. | |
14 # In these cases, the base type (e.g., Window) provides restricted access | |
15 # while the subtype (e.g., LocalWindow) provides full access to the | |
16 # corresponding objects if there are from the same frame. | |
17 _secure_base_types = { | |
18 'LocalWindow': 'Window', | |
19 'LocalLocation': 'Location', | |
20 'LocalHistory': 'History', | |
21 } | |
10 | 22 |
11 class HtmlDartGenerator(object): | 23 class HtmlDartGenerator(object): |
12 def __init__(self, interface, options): | 24 def __init__(self, interface, options): |
25 self._database = options.database | |
13 self._interface = interface | 26 self._interface = interface |
27 self._type_registry = options.type_registry | |
28 self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) | |
29 self._renamer = options.renamer | |
14 | 30 |
15 def EmitAttributeDocumentation(self, attribute): | 31 def EmitAttributeDocumentation(self, attribute): |
16 dom_name = DartDomNameOfAttribute(attribute) | 32 dom_name = DartDomNameOfAttribute(attribute) |
17 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', | 33 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', |
18 DOMINTERFACE=attribute.doc_js_interface_name, | 34 DOMINTERFACE=attribute.doc_js_interface_name, |
19 DOMNAME=dom_name) | 35 DOMNAME=dom_name) |
20 | 36 |
21 def EmitOperationDocumentation(self, operation): | 37 def EmitOperationDocumentation(self, operation): |
22 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', | 38 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', |
23 DOMINTERFACE=operation.overloads[0].doc_js_interface_name, | 39 DOMINTERFACE=operation.overloads[0].doc_js_interface_name, |
24 DOMNAME=operation.name) | 40 DOMNAME=operation.name) |
25 | 41 |
42 def EmitEventGetter(self, events_class_name): | |
43 self._members_emitter.Emit( | |
44 '\n /**' | |
45 '\n * @domName EventTarget.addEventListener, ' | |
46 'EventTarget.removeEventListener, EventTarget.dispatchEvent' | |
47 '\n */' | |
48 '\n $TYPE get on =>\n new $TYPE(this);\n', | |
49 TYPE=events_class_name) | |
50 | |
51 def AddMembers(self, interface, declare_only=False): | |
vsm
2012/11/07 22:31:28
Is declare_only ever True now?
blois
2012/11/08 00:08:34
Yes, this is used for merged classes in Dartium.
| |
52 for const in sorted(interface.constants, ConstantOutputOrder): | |
53 self.AddConstant(const) | |
54 | |
55 for attr in sorted(interface.attributes, ConstantOutputOrder): | |
56 if attr.type.id != 'EventListener': | |
57 self.AddAttribute(attr, declare_only) | |
58 | |
59 # The implementation should define an indexer if the interface directly | |
60 # extends List. | |
61 element_type = None | |
62 requires_indexer = False | |
63 if self._interface_type_info.list_item_type(): | |
64 self.AddIndexer(self._interface_type_info.list_item_type()) | |
65 else: | |
66 for parent in self._database.Hierarchy(self._interface): | |
67 if parent == self._interface: | |
68 continue | |
69 parent_type_info = self._type_registry.TypeInfo(parent.id) | |
70 if parent_type_info.list_item_type(): | |
71 self.AmendIndexer(parent_type_info.list_item_type()) | |
72 break | |
73 | |
74 # Group overloaded operations by id | |
75 operationsById = {} | |
76 for operation in interface.operations: | |
77 if operation.id not in operationsById: | |
78 operationsById[operation.id] = [] | |
79 operationsById[operation.id].append(operation) | |
80 | |
81 # Generate operations | |
82 for id in sorted(operationsById.keys()): | |
83 operations = operationsById[id] | |
84 info = AnalyzeOperation(interface, operations) | |
85 self.AddOperation(info, declare_only) | |
86 | |
87 def AddSecondaryMembers(self, interface): | |
88 # With multiple inheritance, attributes and operations of non-first | |
89 # interfaces need to be added. Sometimes the attribute or operation is | |
90 # defined in the current interface as well as a parent. In that case we | |
91 # avoid making a duplicate definition and pray that the signatures match. | |
92 secondary_parents = self._TransitiveSecondaryParents(interface) | |
93 for parent_interface in sorted(secondary_parents): | |
94 if isinstance(parent_interface, str): # IsDartCollectionType(parent_inter face) | |
vsm
2012/11/07 22:31:28
nit: line length
blois
2012/11/08 00:08:34
Done.
| |
95 continue | |
96 for attr in sorted(parent_interface.attributes, ConstantOutputOrder): | |
97 if not FindMatchingAttribute(interface, attr): | |
98 self.SecondaryContext(parent_interface) | |
99 self.AddAttribute(attr) | |
100 | |
101 # Group overloaded operations by id | |
102 operationsById = {} | |
103 for operation in parent_interface.operations: | |
104 if operation.id not in operationsById: | |
105 operationsById[operation.id] = [] | |
106 operationsById[operation.id].append(operation) | |
107 | |
108 # Generate operations | |
109 for id in sorted(operationsById.keys()): | |
110 if not any(op.id == id for op in interface.operations): | |
111 operations = operationsById[id] | |
112 info = AnalyzeOperation(interface, operations) | |
113 self.SecondaryContext(parent_interface) | |
114 self.AddOperation(info) | |
115 | |
116 def AddAttribute(self, attribute, declare_only=False): | |
117 dom_name = DartDomNameOfAttribute(attribute) | |
118 html_name = self._renamer.RenameMember( | |
119 self._interface.id, attribute, dom_name, 'get:') | |
120 if not html_name or self._IsPrivate(html_name): | |
121 return | |
122 | |
123 html_setter_name = self._renamer.RenameMember( | |
124 self._interface.id, attribute, dom_name, 'set:') | |
125 read_only = (attribute.is_read_only or 'Replaceable' in attribute.ext_attrs | |
126 or not html_setter_name) | |
127 | |
128 # We don't yet handle inconsistent renames of the getter and setter yet. | |
129 assert(not html_setter_name or html_name == html_setter_name) | |
130 | |
131 if declare_only: | |
132 self.DeclareAttribute(attribute, | |
133 self.SecureOutputType(attribute.type.id), html_name, read_only) | |
134 else: | |
135 self.EmitAttribute(attribute, html_name, read_only) | |
136 | |
137 def AddOperation(self, info, declare_only=False): | |
138 """ | |
139 Arguments: | |
140 operations - contains the overloads, one or more operations with the same | |
141 name. | |
142 """ | |
143 # FIXME: When we pass in operations[0] below, we're assuming all | |
144 # overloaded operations have the same security attributes. This | |
145 # is currently true, but we should consider filtering earlier or | |
146 # merging the relevant data into info itself. | |
147 html_name = self._renamer.RenameMember(self._interface.id, | |
148 info.operations[0], | |
149 info.name) | |
150 if not html_name: | |
151 if info.name == 'item': | |
152 # FIXME: item should be renamed to operator[], not removed. | |
153 self.EmitOperation(info, '_item') | |
154 return | |
155 | |
156 if declare_only: | |
157 self.DeclareOperation(info, | |
158 self.SecureOutputType(info.type_name), html_name) | |
159 else: | |
160 self.EmitOperation(info, html_name) | |
161 | |
26 def AdditionalImplementedInterfaces(self): | 162 def AdditionalImplementedInterfaces(self): |
27 # TODO: Include all implemented interfaces, including other Lists. | 163 # TODO: Include all implemented interfaces, including other Lists. |
28 implements = [] | 164 implements = [] |
29 if self._interface_type_info.is_typed_array(): | 165 if self._interface_type_info.is_typed_array(): |
30 element_type = self._interface_type_info.list_item_type() | 166 element_type = self._interface_type_info.list_item_type() |
31 implements.append('List<%s>' % self._DartType(element_type)) | 167 implements.append('List<%s>' % self._DartType(element_type)) |
32 if self._interface_type_info.list_item_type(): | 168 if self._interface_type_info.list_item_type(): |
33 item_type_info = self._type_registry.TypeInfo( | 169 item_type_info = self._type_registry.TypeInfo( |
34 self._interface_type_info.list_item_type()) | 170 self._interface_type_info.list_item_type()) |
35 implements.append('List<%s>' % item_type_info.dart_type()) | 171 implements.append('List<%s>' % item_type_info.dart_type()) |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 | 215 |
80 def DeclareOperation(self, operation, type_name, html_name): | 216 def DeclareOperation(self, operation, type_name, html_name): |
81 # Declares an operation but does not include the code to invoke it. | 217 # Declares an operation but does not include the code to invoke it. |
82 self.EmitOperationDocumentation(operation) | 218 self.EmitOperationDocumentation(operation) |
83 self._members_emitter.Emit( | 219 self._members_emitter.Emit( |
84 '\n' | 220 '\n' |
85 ' $TYPE $NAME($PARAMS);\n', | 221 ' $TYPE $NAME($PARAMS);\n', |
86 TYPE=type_name, | 222 TYPE=type_name, |
87 NAME=html_name, | 223 NAME=html_name, |
88 PARAMS=operation.ParametersDeclaration(self._DartType)) | 224 PARAMS=operation.ParametersDeclaration(self._DartType)) |
225 | |
226 def SecureOutputType(self, type_name, is_dart_type=False): | |
227 if is_dart_type: | |
228 dart_name = type_name | |
229 else: | |
230 dart_name = self._DartType(type_name) | |
231 # We only need to secure Window. Only local History and Location are return ed | |
vsm
2012/11/07 22:31:28
nit: line len
blois
2012/11/08 00:08:34
Done.
| |
232 # in generated code. | |
233 if dart_name == 'LocalWindow': | |
234 return _secure_base_types[dart_name] | |
235 return dart_name | |
236 | |
237 def SecureBaseName(self, type_name): | |
238 if type_name in _secure_base_types: | |
239 return _secure_base_types[type_name] | |
240 | |
241 def _TransitiveSecondaryParents(self, interface): | |
242 """Returns a list of all non-primary parents. | |
243 | |
244 The list contains the interface objects for interfaces defined in the | |
245 database, and the name for undefined interfaces. | |
246 """ | |
247 def walk(parents): | |
248 for parent in parents: | |
249 parent_name = parent.type.id | |
250 if parent_name == 'EventTarget': | |
251 # Currently EventTarget is implemented as a mixin, not a proper | |
252 # super interface---ignore its members. | |
253 continue | |
254 if IsDartCollectionType(parent_name): | |
255 result.append(parent_name) | |
256 continue | |
257 if self._database.HasInterface(parent_name): | |
258 parent_interface = self._database.GetInterface(parent_name) | |
259 result.append(parent_interface) | |
260 walk(parent_interface.parents) | |
261 | |
262 result = [] | |
263 if interface.parents: | |
264 parent = interface.parents[0] | |
265 if IsPureInterface(parent.type.id): | |
266 walk(interface.parents) | |
267 else: | |
268 walk(interface.parents[1:]) | |
269 return result | |
270 | |
271 def _DartType(self, type_name): | |
272 return self._type_registry.DartType(type_name) | |
273 | |
274 def _IsPrivate(self, name): | |
275 return name.startswith('_') | |
OLD | NEW |