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 import emitter | 9 import emitter |
10 from generator import AnalyzeOperation, ConstantOutputOrder, \ | 10 from generator import AnalyzeOperation, ConstantOutputOrder, \ |
11 DartDomNameOfAttribute, FindMatchingAttribute, IsDartCollectionType, \ | 11 DartDomNameOfAttribute, FindMatchingAttribute, IsDartCollectionType, \ |
12 IsPureInterface, TypeOrNothing, ConvertToFuture, GetCallbackInfo | 12 IsPureInterface, TypeOrNothing, ConvertToFuture, GetCallbackInfo |
13 from htmlrenamer import convert_to_future_members | 13 from copy import deepcopy |
| 14 from htmlrenamer import convert_to_future_members, keep_overloaded_members, \ |
| 15 private_html_members, renamed_html_members, renamed_overloads, \ |
| 16 removed_html_members |
| 17 import logging |
| 18 import monitored |
| 19 import sys |
| 20 |
| 21 _logger = logging.getLogger('htmldartgenerator') |
14 | 22 |
15 # Types that are accessible cross-frame in a limited fashion. | 23 # Types that are accessible cross-frame in a limited fashion. |
16 # In these cases, the base type (e.g., WindowBase) provides restricted access | 24 # In these cases, the base type (e.g., WindowBase) provides restricted access |
17 # while the subtype (e.g., Window) provides full access to the | 25 # while the subtype (e.g., Window) provides full access to the |
18 # corresponding objects if there are from the same frame. | 26 # corresponding objects if there are from the same frame. |
19 _secure_base_types = { | 27 _secure_base_types = { |
20 'Window': 'WindowBase', | 28 'Window': 'WindowBase', |
21 'Location': 'LocationBase', | 29 'Location': 'LocationBase', |
22 'History': 'HistoryBase', | 30 'History': 'HistoryBase', |
23 } | 31 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 else: | 84 else: |
77 for parent in self._database.Hierarchy(self._interface): | 85 for parent in self._database.Hierarchy(self._interface): |
78 if parent == self._interface: | 86 if parent == self._interface: |
79 continue | 87 continue |
80 parent_type_info = self._type_registry.TypeInfo(parent.id) | 88 parent_type_info = self._type_registry.TypeInfo(parent.id) |
81 if parent_type_info.list_item_type(): | 89 if parent_type_info.list_item_type(): |
82 self.AmendIndexer(parent_type_info.list_item_type()) | 90 self.AmendIndexer(parent_type_info.list_item_type()) |
83 break | 91 break |
84 | 92 |
85 # Group overloaded operations by name. | 93 # Group overloaded operations by name. |
| 94 self._AddRenamedOverloads(interface) |
86 operationsByName = self._OperationsByName(interface) | 95 operationsByName = self._OperationsByName(interface) |
87 | 96 |
88 # Generate operations. | 97 # Generate operations. |
89 for id in sorted(operationsByName.keys()): | 98 for id in sorted(operationsByName.keys()): |
90 operations = operationsByName[id] | 99 operations = operationsByName[id] |
91 info = AnalyzeOperation(interface, operations) | 100 info = AnalyzeOperation(interface, operations) |
92 self.AddOperation(info, declare_only) | 101 self.AddOperation(info, declare_only) |
93 if ('%s.%s' % (interface.id, info.declared_name) in | 102 if ('%s.%s' % (interface.id, info.declared_name) in |
94 convert_to_future_members): | 103 convert_to_future_members): |
95 self.AddOperation(ConvertToFuture(info), declare_only) | 104 self.AddOperation(ConvertToFuture(info), declare_only) |
(...skipping 16 matching lines...) Expand all Loading... |
112 operationsByName =self._OperationsByName(parent_interface) | 121 operationsByName =self._OperationsByName(parent_interface) |
113 | 122 |
114 # Generate operations. | 123 # Generate operations. |
115 for id in sorted(operationsByName.keys()): | 124 for id in sorted(operationsByName.keys()): |
116 if not any(op.id == id for op in interface.operations): | 125 if not any(op.id == id for op in interface.operations): |
117 operations = operationsByName[id] | 126 operations = operationsByName[id] |
118 info = AnalyzeOperation(interface, operations) | 127 info = AnalyzeOperation(interface, operations) |
119 self.SecondaryContext(parent_interface) | 128 self.SecondaryContext(parent_interface) |
120 self.AddOperation(info) | 129 self.AddOperation(info) |
121 | 130 |
| 131 def _AddRenamedOverloads(self, interface): |
| 132 """The IDL has a number of functions with the same name but that accept |
| 133 different types. This is fine for JavaScript, but results in vague type |
| 134 signatures for Dart. We rename some of these (by adding a new identical |
| 135 operation with a different DartName), and leave the original version in a |
| 136 few specific instances.""" |
| 137 potential_added_operations = set() |
| 138 operations_by_name = self._OperationsByName(interface) |
| 139 already_renamed = [operation.ext_attrs['DartName'] if 'DartName' in |
| 140 operation.ext_attrs else '' for operation in interface.operations] |
| 141 |
| 142 for operation in interface.operations: |
| 143 full_operation_str = self._GetStringRepresentation(interface, operation) |
| 144 if (full_operation_str in renamed_overloads and |
| 145 renamed_overloads[full_operation_str] not in already_renamed): |
| 146 operation.ext_attrs['DartName'] = renamed_overloads[ |
| 147 full_operation_str] |
| 148 potential_added_operations.add(operation.id) |
| 149 self._EnsureNoMultipleTypeSignatures(interface, operation, |
| 150 operations_by_name) |
| 151 self._AddDesiredOverloadedOperations(potential_added_operations, interface, |
| 152 operations_by_name) |
| 153 |
| 154 def _AddDesiredOverloadedOperations(self, potential_added_operations, |
| 155 interface, original_operations_by_name): |
| 156 """For some cases we desire to keep the overloaded version in dart, for |
| 157 simplicity of API, and explain the parameters accepted in documentation.""" |
| 158 updated_operations_by_name = self._OperationsByName(interface) |
| 159 for operation_id in potential_added_operations: |
| 160 if (operation_id not in updated_operations_by_name and |
| 161 '%s.%s' % (interface.id, operation_id) in keep_overloaded_members): |
| 162 for operation in original_operations_by_name[operation_id]: |
| 163 cloned_operation = deepcopy(operation) |
| 164 cloned_operation.ext_attrs['DartName'] = operation_id |
| 165 interface.operations.append(cloned_operation) |
| 166 |
| 167 def _EnsureNoMultipleTypeSignatures(self, interface, operation, |
| 168 operations_by_name): |
| 169 """Make sure that there is now at most one operation with a particular |
| 170 operation.id. If not, stop library generation, and throw an error, requiring |
| 171 programmer input about the best name change before proceeding.""" |
| 172 operation_str = '%s.%s' % (interface.id, operation.id) |
| 173 if (operation.id in operations_by_name and |
| 174 len(operations_by_name[operation.id]) > 1 and |
| 175 len(filter(lambda overload: overload.startswith(operation_str), |
| 176 renamed_overloads.keys())) == 0 and |
| 177 operation_str not in keep_overloaded_members and |
| 178 operation_str not in renamed_html_members and |
| 179 operation_str not in private_html_members and |
| 180 operation_str not in removed_html_members and |
| 181 operation.id != '__getter__' and |
| 182 operation.id != '__setter__' and |
| 183 operation.id != '__delete__'): |
| 184 _logger.error('Multiple type signatures for %s.%s' % ( |
| 185 interface.id, operation.id)) |
| 186 raise Exception('Rename one of the methods in renamed_overloads or add it' |
| 187 ' to keep_overloaded_members.\n' |
| 188 'Generation UNsuccessful.') |
| 189 |
| 190 def _GetStringRepresentation(self, interface, operation): |
| 191 """Given an IDLOperation, return a object-independent representation of the |
| 192 operations's signature.""" |
| 193 return '%s.%s(%s)' % (interface.id, operation.id, ', '.join( |
| 194 ['%s %s' % (arg.type.id, arg.id) for arg in operation.arguments])) |
| 195 |
122 def _OperationsByName(self, interface): | 196 def _OperationsByName(self, interface): |
123 operationsByName = {} | 197 operationsByName = {} |
124 for operation in interface.operations: | 198 for operation in interface.operations: |
125 name = operation.ext_attrs.get('DartName', operation.id) | 199 name = operation.ext_attrs.get('DartName', operation.id) |
126 operationsByName.setdefault(name, []).append(operation) | 200 operationsByName.setdefault(name, []).append(operation) |
127 return operationsByName | 201 return operationsByName |
128 | 202 |
129 def AddConstant(self, constant): | 203 def AddConstant(self, constant): |
130 const_name = self._renamer.RenameMember( | 204 const_name = self._renamer.RenameMember( |
131 self._interface.id, constant, constant.id, 'get:', dartify_name=False) | 205 self._interface.id, constant, constant.id, 'get:', dartify_name=False) |
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 if interface.parents: | 667 if interface.parents: |
594 parent = interface.parents[0] | 668 parent = interface.parents[0] |
595 if IsPureInterface(parent.type.id): | 669 if IsPureInterface(parent.type.id): |
596 walk(interface.parents) | 670 walk(interface.parents) |
597 else: | 671 else: |
598 walk(interface.parents[1:]) | 672 walk(interface.parents[1:]) |
599 return result | 673 return result |
600 | 674 |
601 def _DartType(self, type_name): | 675 def _DartType(self, type_name): |
602 return self._type_registry.DartType(type_name) | 676 return self._type_registry.DartType(type_name) |
OLD | NEW |