Chromium Code Reviews| 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 |