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): |
| 32 """ Emits the MDN dartdoc comment for an attribute. |
| 33 """ |
16 dom_name = DartDomNameOfAttribute(attribute) | 34 dom_name = DartDomNameOfAttribute(attribute) |
17 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', | 35 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', |
18 DOMINTERFACE=attribute.doc_js_interface_name, | 36 DOMINTERFACE=attribute.doc_js_interface_name, |
19 DOMNAME=dom_name) | 37 DOMNAME=dom_name) |
20 | 38 |
21 def EmitOperationDocumentation(self, operation): | 39 def EmitOperationDocumentation(self, operation): |
| 40 """ Emits the MDN dartdoc comment for an operation. |
| 41 """ |
22 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', | 42 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', |
23 DOMINTERFACE=operation.overloads[0].doc_js_interface_name, | 43 DOMINTERFACE=operation.overloads[0].doc_js_interface_name, |
24 DOMNAME=operation.name) | 44 DOMNAME=operation.name) |
25 | 45 |
| 46 def EmitEventGetter(self, events_class_name): |
| 47 self._members_emitter.Emit( |
| 48 '\n /**' |
| 49 '\n * @domName EventTarget.addEventListener, ' |
| 50 'EventTarget.removeEventListener, EventTarget.dispatchEvent' |
| 51 '\n */' |
| 52 '\n $TYPE get on =>\n new $TYPE(this);\n', |
| 53 TYPE=events_class_name) |
| 54 |
| 55 def AddMembers(self, interface, declare_only=False): |
| 56 for const in sorted(interface.constants, ConstantOutputOrder): |
| 57 self.AddConstant(const) |
| 58 |
| 59 for attr in sorted(interface.attributes, ConstantOutputOrder): |
| 60 if attr.type.id != 'EventListener': |
| 61 self.AddAttribute(attr, declare_only) |
| 62 |
| 63 # The implementation should define an indexer if the interface directly |
| 64 # extends List. |
| 65 element_type = None |
| 66 requires_indexer = False |
| 67 if self._interface_type_info.list_item_type(): |
| 68 self.AddIndexer(self._interface_type_info.list_item_type()) |
| 69 else: |
| 70 for parent in self._database.Hierarchy(self._interface): |
| 71 if parent == self._interface: |
| 72 continue |
| 73 parent_type_info = self._type_registry.TypeInfo(parent.id) |
| 74 if parent_type_info.list_item_type(): |
| 75 self.AmendIndexer(parent_type_info.list_item_type()) |
| 76 break |
| 77 |
| 78 # Group overloaded operations by id. |
| 79 operationsById = {} |
| 80 for operation in interface.operations: |
| 81 if operation.id not in operationsById: |
| 82 operationsById[operation.id] = [] |
| 83 operationsById[operation.id].append(operation) |
| 84 |
| 85 # Generate operations. |
| 86 for id in sorted(operationsById.keys()): |
| 87 operations = operationsById[id] |
| 88 info = AnalyzeOperation(interface, operations) |
| 89 self.AddOperation(info, declare_only) |
| 90 |
| 91 def AddSecondaryMembers(self, interface): |
| 92 # With multiple inheritance, attributes and operations of non-first |
| 93 # interfaces need to be added. Sometimes the attribute or operation is |
| 94 # defined in the current interface as well as a parent. In that case we |
| 95 # avoid making a duplicate definition and pray that the signatures match. |
| 96 secondary_parents = self._TransitiveSecondaryParents(interface) |
| 97 for parent_interface in sorted(secondary_parents): |
| 98 if isinstance(parent_interface, str): |
| 99 continue |
| 100 for attr in sorted(parent_interface.attributes, ConstantOutputOrder): |
| 101 if not FindMatchingAttribute(interface, attr): |
| 102 self.SecondaryContext(parent_interface) |
| 103 self.AddAttribute(attr) |
| 104 |
| 105 # Group overloaded operations by id. |
| 106 operationsById = {} |
| 107 for operation in parent_interface.operations: |
| 108 if operation.id not in operationsById: |
| 109 operationsById[operation.id] = [] |
| 110 operationsById[operation.id].append(operation) |
| 111 |
| 112 # Generate operations. |
| 113 for id in sorted(operationsById.keys()): |
| 114 if not any(op.id == id for op in interface.operations): |
| 115 operations = operationsById[id] |
| 116 info = AnalyzeOperation(interface, operations) |
| 117 self.SecondaryContext(parent_interface) |
| 118 self.AddOperation(info) |
| 119 |
| 120 def AddAttribute(self, attribute, declare_only=False): |
| 121 """ Adds an attribute to the generated class. |
| 122 Arguments: |
| 123 attribute - The attribute which is to be added. |
| 124 declare_only- True if the attribute should be declared as an abstract |
| 125 member and not include invocation code. |
| 126 """ |
| 127 dom_name = DartDomNameOfAttribute(attribute) |
| 128 attr_name = self._renamer.RenameMember( |
| 129 self._interface.id, attribute, dom_name, 'get:') |
| 130 if not attr_name or self._IsPrivate(attr_name): |
| 131 return |
| 132 |
| 133 html_setter_name = self._renamer.RenameMember( |
| 134 self._interface.id, attribute, dom_name, 'set:') |
| 135 read_only = (attribute.is_read_only or 'Replaceable' in attribute.ext_attrs |
| 136 or not html_setter_name) |
| 137 |
| 138 # We don't yet handle inconsistent renames of the getter and setter yet. |
| 139 assert(not html_setter_name or attr_name == html_setter_name) |
| 140 |
| 141 if declare_only: |
| 142 self.DeclareAttribute(attribute, |
| 143 self.SecureOutputType(attribute.type.id), attr_name, read_only) |
| 144 else: |
| 145 self.EmitAttribute(attribute, attr_name, read_only) |
| 146 |
| 147 def AddOperation(self, info, declare_only=False): |
| 148 """ Adds an operation to the generated class. |
| 149 Arguments: |
| 150 info - The operation info of the operation to be added. |
| 151 declare_only- True if the operation should be declared as an abstract |
| 152 member and not include invocation code. |
| 153 """ |
| 154 # FIXME: When we pass in operations[0] below, we're assuming all |
| 155 # overloaded operations have the same security attributes. This |
| 156 # is currently true, but we should consider filtering earlier or |
| 157 # merging the relevant data into info itself. |
| 158 method_name = self._renamer.RenameMember(self._interface.id, |
| 159 info.operations[0], |
| 160 info.name) |
| 161 if not method_name: |
| 162 if info.name == 'item': |
| 163 # FIXME: item should be renamed to operator[], not removed. |
| 164 self.EmitOperation(info, '_item') |
| 165 return |
| 166 |
| 167 if declare_only: |
| 168 self.DeclareOperation(info, |
| 169 self.SecureOutputType(info.type_name), method_name) |
| 170 else: |
| 171 self.EmitOperation(info, method_name) |
| 172 |
26 def AdditionalImplementedInterfaces(self): | 173 def AdditionalImplementedInterfaces(self): |
27 # TODO: Include all implemented interfaces, including other Lists. | 174 # TODO: Include all implemented interfaces, including other Lists. |
28 implements = [] | 175 implements = [] |
29 if self._interface_type_info.is_typed_array(): | 176 if self._interface_type_info.is_typed_array(): |
30 element_type = self._interface_type_info.list_item_type() | 177 element_type = self._interface_type_info.list_item_type() |
31 implements.append('List<%s>' % self._DartType(element_type)) | 178 implements.append('List<%s>' % self._DartType(element_type)) |
32 if self._interface_type_info.list_item_type(): | 179 if self._interface_type_info.list_item_type(): |
33 item_type_info = self._type_registry.TypeInfo( | 180 item_type_info = self._type_registry.TypeInfo( |
34 self._interface_type_info.list_item_type()) | 181 self._interface_type_info.list_item_type()) |
35 implements.append('List<%s>' % item_type_info.dart_type()) | 182 implements.append('List<%s>' % item_type_info.dart_type()) |
36 return implements | 183 return implements |
37 | 184 |
38 def AddConstructors(self, constructors, factory_provider, class_name, | 185 def AddConstructors(self, constructors, factory_provider, class_name, |
39 base_class): | 186 base_class): |
| 187 """ Adds all of the constructors. |
| 188 Arguments: |
| 189 constructors - List of the constructors to be added. |
| 190 factory_provider - Name of the factory provider for this class. |
| 191 class_name - The name of this class. |
| 192 base_class - The name of the base class which this extends. |
| 193 """ |
40 for constructor_info in constructors: | 194 for constructor_info in constructors: |
41 self._AddConstructor(constructor_info, factory_provider) | 195 self._AddConstructor(constructor_info, factory_provider) |
42 | 196 |
43 typed_array_type = None | 197 typed_array_type = None |
44 for interface in self._database.Hierarchy(self._interface): | 198 for interface in self._database.Hierarchy(self._interface): |
45 type_info = self._type_registry.TypeInfo(interface.id) | 199 type_info = self._type_registry.TypeInfo(interface.id) |
46 if type_info.is_typed_array(): | 200 if type_info.is_typed_array(): |
47 typed_array_type = type_info.list_item_type() | 201 typed_array_type = type_info.list_item_type() |
48 break | 202 break |
49 if typed_array_type: | 203 if typed_array_type: |
50 self._members_emitter.Emit( | 204 self._members_emitter.Emit( |
51 '\n' | 205 '\n' |
52 ' factory $CTOR(int length) =>\n' | 206 ' factory $CTOR(int length) =>\n' |
53 ' $FACTORY.create$(CTOR)(length);\n' | 207 ' $FACTORY.create$(CTOR)(length);\n' |
54 '\n' | 208 '\n' |
55 ' factory $CTOR.fromList(List<$TYPE> list) =>\n' | 209 ' factory $CTOR.fromList(List<$TYPE> list) =>\n' |
56 ' $FACTORY.create$(CTOR)_fromList(list);\n' | 210 ' $FACTORY.create$(CTOR)_fromList(list);\n' |
57 '\n' | 211 '\n' |
58 ' factory $CTOR.fromBuffer(ArrayBuffer buffer, [int byteOffset, int l
ength]) => \n' | 212 ' factory $CTOR.fromBuffer(ArrayBuffer buffer, ' |
| 213 '[int byteOffset, int length]) => \n' |
59 ' $FACTORY.create$(CTOR)_fromBuffer(buffer, byteOffset, length);\n'
, | 214 ' $FACTORY.create$(CTOR)_fromBuffer(buffer, byteOffset, length);\n'
, |
60 CTOR=self._interface.id, | 215 CTOR=self._interface.id, |
61 TYPE=self._DartType(typed_array_type), | 216 TYPE=self._DartType(typed_array_type), |
62 FACTORY=factory_provider) | 217 FACTORY=factory_provider) |
63 | 218 |
64 def _AddConstructor(self, constructor_info, factory_provider): | 219 def _AddConstructor(self, constructor_info, factory_provider): |
65 constructor_info.GenerateFactoryInvocation( | 220 constructor_info.GenerateFactoryInvocation( |
66 self._DartType, self._members_emitter, factory_provider) | 221 self._DartType, self._members_emitter, factory_provider) |
67 | 222 |
68 def DeclareAttribute(self, attribute, type_name, html_name, read_only): | 223 def DeclareAttribute(self, attribute, type_name, attr_name, read_only): |
69 # Declares an attribute but does not include the code to invoke it. | 224 """ Declares an attribute but does not include the code to invoke it. |
| 225 """ |
70 self.EmitAttributeDocumentation(attribute) | 226 self.EmitAttributeDocumentation(attribute) |
71 if read_only: | 227 if read_only: |
72 template = '\n $TYPE get $NAME;\n' | 228 template = '\n $TYPE get $NAME;\n' |
73 else: | 229 else: |
74 template = '\n $TYPE $NAME;\n' | 230 template = '\n $TYPE $NAME;\n' |
75 | 231 |
76 self._members_emitter.Emit(template, | 232 self._members_emitter.Emit(template, |
77 NAME=html_name, | 233 NAME=attr_name, |
78 TYPE=type_name) | 234 TYPE=type_name) |
79 | 235 |
80 def DeclareOperation(self, operation, type_name, html_name): | 236 def DeclareOperation(self, operation, return_type_name, method_name): |
81 # Declares an operation but does not include the code to invoke it. | 237 """ Declares an operation but does not include the code to invoke it. |
| 238 Arguments: |
| 239 operation - The operation to be declared. |
| 240 return_type_name - The name of the return type. |
| 241 method_name - The name of the method. |
| 242 """ |
82 self.EmitOperationDocumentation(operation) | 243 self.EmitOperationDocumentation(operation) |
83 self._members_emitter.Emit( | 244 self._members_emitter.Emit( |
84 '\n' | 245 '\n' |
85 ' $TYPE $NAME($PARAMS);\n', | 246 ' $TYPE $NAME($PARAMS);\n', |
86 TYPE=type_name, | 247 TYPE=return_type_name, |
87 NAME=html_name, | 248 NAME=method_name, |
88 PARAMS=operation.ParametersDeclaration(self._DartType)) | 249 PARAMS=operation.ParametersDeclaration(self._DartType)) |
| 250 |
| 251 def SecureOutputType(self, type_name, is_dart_type=False): |
| 252 """ Converts the type name to the secure type name for return types. |
| 253 """ |
| 254 if is_dart_type: |
| 255 dart_name = type_name |
| 256 else: |
| 257 dart_name = self._DartType(type_name) |
| 258 # We only need to secure Window. Only local History and Location are |
| 259 # returned in generated code. |
| 260 assert(dart_name != 'History' and dart_name != 'Location') |
| 261 if dart_name == 'LocalWindow': |
| 262 return _secure_base_types[dart_name] |
| 263 return dart_name |
| 264 |
| 265 def SecureBaseName(self, type_name): |
| 266 if type_name in _secure_base_types: |
| 267 return _secure_base_types[type_name] |
| 268 |
| 269 def _TransitiveSecondaryParents(self, interface): |
| 270 """Returns a list of all non-primary parents. |
| 271 |
| 272 The list contains the interface objects for interfaces defined in the |
| 273 database, and the name for undefined interfaces. |
| 274 """ |
| 275 def walk(parents): |
| 276 for parent in parents: |
| 277 parent_name = parent.type.id |
| 278 if parent_name == 'EventTarget': |
| 279 # Currently EventTarget is implemented as a mixin, not a proper |
| 280 # super interface---ignore its members. |
| 281 continue |
| 282 if IsDartCollectionType(parent_name): |
| 283 result.append(parent_name) |
| 284 continue |
| 285 if self._database.HasInterface(parent_name): |
| 286 parent_interface = self._database.GetInterface(parent_name) |
| 287 result.append(parent_interface) |
| 288 walk(parent_interface.parents) |
| 289 |
| 290 result = [] |
| 291 if interface.parents: |
| 292 parent = interface.parents[0] |
| 293 if IsPureInterface(parent.type.id): |
| 294 walk(interface.parents) |
| 295 else: |
| 296 walk(interface.parents[1:]) |
| 297 return result |
| 298 |
| 299 def _DartType(self, type_name): |
| 300 return self._type_registry.DartType(type_name) |
| 301 |
| 302 def _IsPrivate(self, name): |
| 303 return name.startswith('_') |
OLD | NEW |