| 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 generates Dart APIs from the IDL database.""" | 6 """This module generates Dart APIs from the IDL database.""" |
| 7 | 7 |
| 8 import emitter | 8 import emitter |
| 9 import idlnode | 9 import idlnode |
| 10 import logging | 10 import logging |
| 11 import multiemitter | 11 import multiemitter |
| 12 import os | 12 import os |
| 13 import re | 13 import re |
| 14 import shutil | 14 import shutil |
| 15 from systembase import * |
| 16 from systemfrog import * |
| 17 from systemhtml import * |
| 15 | 18 |
| 16 _logger = logging.getLogger('dartgenerator') | 19 _logger = logging.getLogger('dartgenerator') |
| 17 | 20 |
| 18 # IDL->Dart primitive types conversion. | |
| 19 _idl_to_dart_type_conversions = { | |
| 20 'any': 'Object', | |
| 21 'any[]': 'List', | |
| 22 'custom': 'Dynamic', | |
| 23 'boolean': 'bool', | |
| 24 'DOMObject': 'Object', | |
| 25 'DOMString': 'String', | |
| 26 'DOMStringList': 'List<String>', | |
| 27 'DOMTimeStamp': 'int', | |
| 28 'Date': 'Date', | |
| 29 # Map to num to enable callers to pass in Dart int, rational | |
| 30 # types. Our implementations will need to convert these to | |
| 31 # doubles or floats as needed. | |
| 32 'double': 'num', | |
| 33 'float': 'num', | |
| 34 'int': 'int', | |
| 35 # Map to extra precision - int is a bignum in Dart. | |
| 36 'long': 'int', | |
| 37 'long long': 'int', | |
| 38 'object': 'Object', | |
| 39 # Map to extra precision - int is a bignum in Dart. | |
| 40 'short': 'int', | |
| 41 'string': 'String', | |
| 42 'void': 'void', | |
| 43 'Array': 'List', | |
| 44 'sequence': 'List', | |
| 45 # TODO(sra): Come up with some meaningful name so that where this appears in | |
| 46 # the documentation, the user is made aware that only a limited subset of | |
| 47 # serializable types are actually permitted. | |
| 48 'SerializedScriptValue': 'Dynamic', | |
| 49 # TODO(vsm): Automatically recognize types defined in src. | |
| 50 'TimeoutHandler': 'TimeoutHandler', | |
| 51 'RequestAnimationFrameCallback': 'RequestAnimationFrameCallback', | |
| 52 | |
| 53 # TODO(sra): Flags is really a dictionary: {create:bool, exclusive:bool} | |
| 54 # http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#the-flags-interfa
ce | |
| 55 'WebKitFlags': 'Object', | |
| 56 } | |
| 57 | |
| 58 _dart_to_idl_type_conversions = dict((v,k) for k, v in | |
| 59 _idl_to_dart_type_conversions.iteritems()) | |
| 60 | |
| 61 | |
| 62 # | |
| 63 # Identifiers that are used in the IDL than need to be treated specially because | |
| 64 # *some* JavaScript processors forbid them as properties. | |
| 65 # | |
| 66 _javascript_keywords = ['delete', 'continue'] | |
| 67 | |
| 68 # | |
| 69 # Interface version of the DOM needs to delegate typed array constructors to a | |
| 70 # factory provider. | |
| 71 # | |
| 72 _interface_factories = { | |
| 73 'Float32Array': '_TypedArrayFactoryProvider', | |
| 74 'Float64Array': '_TypedArrayFactoryProvider', | |
| 75 'Int8Array': '_TypedArrayFactoryProvider', | |
| 76 'Int16Array': '_TypedArrayFactoryProvider', | |
| 77 'Int32Array': '_TypedArrayFactoryProvider', | |
| 78 'Uint8Array': '_TypedArrayFactoryProvider', | |
| 79 'Uint16Array': '_TypedArrayFactoryProvider', | |
| 80 'Uint32Array': '_TypedArrayFactoryProvider', | |
| 81 'Uint8ClampedArray': '_TypedArrayFactoryProvider', | |
| 82 } | |
| 83 | |
| 84 # | |
| 85 # Custom methods that must be implemented by hand. | |
| 86 # | |
| 87 _custom_methods = set([ | |
| 88 ('DOMWindow', 'setInterval'), | |
| 89 ('DOMWindow', 'setTimeout'), | |
| 90 ('WorkerContext', 'setInterval'), | |
| 91 ('WorkerContext', 'setTimeout'), | |
| 92 ('CanvasRenderingContext2D', 'setFillStyle'), | |
| 93 ('CanvasRenderingContext2D', 'setStrokeStyle'), | |
| 94 ('CanvasRenderingContext2D', 'setFillStyle'), | |
| 95 ]) | |
| 96 | |
| 97 # | |
| 98 # Custom getters that must be implemented by hand. | |
| 99 # | |
| 100 _custom_getters = set([ | |
| 101 ('DOMWindow', 'localStorage'), | |
| 102 ]) | |
| 103 | |
| 104 # | |
| 105 # Custom native specs for the Frog dom. | |
| 106 # | |
| 107 _frog_dom_custom_native_specs = { | |
| 108 # Decorate the singleton Console object, if present (workers do not have a | |
| 109 # console). | |
| 110 'Console': "=(typeof console == 'undefined' ? {} : console)", | |
| 111 | |
| 112 # DOMWindow aliased with global scope. | |
| 113 'DOMWindow': '@*DOMWindow', | |
| 114 } | |
| 115 | |
| 116 # | |
| 117 # Simple method substitution when one method had different names on different | |
| 118 # browsers, but are otherwise identical. The alternates are tried in order and | |
| 119 # the first one defined is used. | |
| 120 # | |
| 121 # This can be probably be removed when Chrome renames initWebKitWheelEvent to | |
| 122 # initWheelEvent. | |
| 123 # | |
| 124 _alternate_methods = { | |
| 125 ('WheelEvent', 'initWheelEvent'): ['initWebKitWheelEvent', 'initWheelEvent'] | |
| 126 } | |
| 127 | |
| 128 | |
| 129 def _MatchSourceFilter(filter, thing): | |
| 130 if not filter: | |
| 131 return True | |
| 132 else: | |
| 133 return any(token in thing.annotations for token in filter) | |
| 134 | |
| 135 def _IsDartListType(type): | |
| 136 return type == 'List' or type.startswith('List<') | |
| 137 | |
| 138 def _IsDartCollectionType(type): | |
| 139 return _IsDartListType(type) | |
| 140 | |
| 141 | |
| 142 class DartGenerator(object): | 21 class DartGenerator(object): |
| 143 """Utilities to generate Dart APIs and corresponding JavaScript.""" | 22 """Utilities to generate Dart APIs and corresponding JavaScript.""" |
| 144 | 23 |
| 145 def __init__(self, auxiliary_dir, template_dir, base_package): | 24 def __init__(self, auxiliary_dir, template_dir, base_package): |
| 146 """Constructor for the DartGenerator. | 25 """Constructor for the DartGenerator. |
| 147 | 26 |
| 148 Args: | 27 Args: |
| 149 auxiliary_dir -- location of auxiliary handwritten classes | 28 auxiliary_dir -- location of auxiliary handwritten classes |
| 150 template_dir -- location of template files | 29 template_dir -- location of template files |
| 151 base_package -- the base package name for the generated code. | 30 base_package -- the base package name for the generated code. |
| 152 """ | 31 """ |
| 153 self._auxiliary_dir = auxiliary_dir | 32 self._auxiliary_dir = auxiliary_dir |
| 154 self._template_dir = template_dir | 33 self._template_dir = template_dir |
| 155 self._base_package = base_package | 34 self._base_package = base_package |
| 156 self._auxiliary_files = {} | 35 self._auxiliary_files = {} |
| 157 self._dart_templates_re = re.compile(r'[\w.:]+<([\w\.<>:]+)>') | 36 self._dart_templates_re = re.compile(r'[\w.:]+<([\w\.<>:]+)>') |
| 158 | 37 |
| 159 self._emitters = None # set later | 38 self._emitters = None # set later |
| 160 | 39 |
| 161 | 40 |
| 162 def _StripModules(self, type_name): | 41 def _StripModules(self, type_name): |
| 163 return type_name.split('::')[-1] | 42 return type_name.split('::')[-1] |
| 164 | 43 |
| 165 def _IsPrimitiveType(self, type_name): | |
| 166 return (self._ConvertPrimitiveType(type_name) is not None or | |
| 167 type_name in _dart_to_idl_type_conversions) | |
| 168 | |
| 169 def _IsCompoundType(self, database, type_name): | 44 def _IsCompoundType(self, database, type_name): |
| 170 if self._IsPrimitiveType(type_name): | 45 if IsPrimitiveType(type_name): |
| 171 return True | 46 return True |
| 172 | 47 |
| 173 striped_type_name = self._StripModules(type_name) | 48 striped_type_name = self._StripModules(type_name) |
| 174 if database.HasInterface(striped_type_name): | 49 if database.HasInterface(striped_type_name): |
| 175 return True | 50 return True |
| 176 | 51 |
| 177 dart_template_match = self._dart_templates_re.match(type_name) | 52 dart_template_match = self._dart_templates_re.match(type_name) |
| 178 if dart_template_match: | 53 if dart_template_match: |
| 179 # Dart templates | 54 # Dart templates |
| 180 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] | 55 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] |
| 181 sub_type_name = dart_template_match.group(1) | 56 sub_type_name = dart_template_match.group(1) |
| 182 return (self._IsCompoundType(database, parent_type_name) and | 57 return (self._IsCompoundType(database, parent_type_name) and |
| 183 self._IsCompoundType(database, sub_type_name)) | 58 self._IsCompoundType(database, sub_type_name)) |
| 184 return False | 59 return False |
| 185 | 60 |
| 186 def _IsDartType(self, type_name): | 61 def _IsDartType(self, type_name): |
| 187 return '.' in type_name | 62 return '.' in type_name |
| 188 | 63 |
| 189 def _ConvertPrimitiveType(self, type_name): | |
| 190 if type_name.startswith('unsigned '): | |
| 191 type_name = type_name[len('unsigned '):] | |
| 192 | |
| 193 if type_name in _idl_to_dart_type_conversions: | |
| 194 # Primitive type conversion | |
| 195 return _idl_to_dart_type_conversions[type_name] | |
| 196 return None | |
| 197 | |
| 198 def LoadAuxiliary(self): | 64 def LoadAuxiliary(self): |
| 199 def Visitor(_, dirname, names): | 65 def Visitor(_, dirname, names): |
| 200 for name in names: | 66 for name in names: |
| 201 if name.endswith('.dart'): | 67 if name.endswith('.dart'): |
| 202 name = name[0:-5] # strip off ".dart" | 68 name = name[0:-5] # strip off ".dart" |
| 203 self._auxiliary_files[name] = os.path.join(dirname, name) | 69 self._auxiliary_files[name] = os.path.join(dirname, name) |
| 204 os.path.walk(self._auxiliary_dir, Visitor, None) | 70 os.path.walk(self._auxiliary_dir, Visitor, None) |
| 205 | 71 |
| 206 def RenameTypes(self, database, conversion_table=None): | 72 def RenameTypes(self, database, conversion_table, rename_javascript_binding_na
mes): |
| 207 """Renames interfaces using the given conversion table. | 73 """Renames interfaces using the given conversion table. |
| 208 | 74 |
| 209 References through all interfaces will be renamed as well. | 75 References through all interfaces will be renamed as well. |
| 210 | 76 |
| 211 Args: | 77 Args: |
| 212 database: the database to apply the renames to. | 78 database: the database to apply the renames to. |
| 213 conversion_table: maps old names to new names. | 79 conversion_table: maps old names to new names. |
| 214 """ | 80 """ |
| 215 | 81 |
| 216 if conversion_table is None: | 82 if conversion_table is None: |
| 217 conversion_table = {} | 83 conversion_table = {} |
| 218 | 84 |
| 219 # Rename interfaces: | 85 # Rename interfaces: |
| 220 for old_name, new_name in conversion_table.items(): | 86 for old_name, new_name in conversion_table.items(): |
| 221 if database.HasInterface(old_name): | 87 if database.HasInterface(old_name): |
| 222 _logger.info('renaming interface %s to %s' % | 88 _logger.info('renaming interface %s to %s' % (old_name, new_name)) |
| 223 (old_name, new_name)) | |
| 224 interface = database.GetInterface(old_name) | 89 interface = database.GetInterface(old_name) |
| 225 database.DeleteInterface(old_name) | 90 database.DeleteInterface(old_name) |
| 226 if not database.HasInterface(new_name): | 91 if not database.HasInterface(new_name): |
| 227 interface.id = new_name | 92 interface.id = new_name |
| 228 database.AddInterface(interface) | 93 database.AddInterface(interface) |
| 229 | 94 else: |
| 95 new_interface = database.GetInterface(new_name) |
| 96 new_interface.merge(interface) |
| 97 |
| 98 interface.javascript_binding_name = (old_name if rename_javascript_bindi
ng_names |
| 99 else new_name) |
| 100 |
| 230 # Fix references: | 101 # Fix references: |
| 231 for interface in database.GetInterfaces(): | 102 for interface in database.GetInterfaces(): |
| 232 for idl_type in interface.all(idlnode.IDLType): | 103 for idl_type in interface.all(idlnode.IDLType): |
| 233 type_name = self._StripModules(idl_type.id) | 104 type_name = self._StripModules(idl_type.id) |
| 234 if type_name in conversion_table: | 105 if type_name in conversion_table: |
| 235 idl_type.id = conversion_table[type_name] | 106 idl_type.id = conversion_table[type_name] |
| 236 | 107 |
| 237 def FilterMembersWithUnidentifiedTypes(self, database): | 108 def FilterMembersWithUnidentifiedTypes(self, database): |
| 238 """Removes unidentified types. | 109 """Removes unidentified types. |
| 239 | 110 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 258 interface.attributes = filter(IsIdentified, interface.attributes) | 129 interface.attributes = filter(IsIdentified, interface.attributes) |
| 259 interface.operations = filter(IsIdentified, interface.operations) | 130 interface.operations = filter(IsIdentified, interface.operations) |
| 260 interface.parents = filter(IsIdentified, interface.parents) | 131 interface.parents = filter(IsIdentified, interface.parents) |
| 261 | 132 |
| 262 def ConvertToDartTypes(self, database): | 133 def ConvertToDartTypes(self, database): |
| 263 """Converts all IDL types to Dart primitives or qualified types""" | 134 """Converts all IDL types to Dart primitives or qualified types""" |
| 264 | 135 |
| 265 def ConvertType(interface, type_name): | 136 def ConvertType(interface, type_name): |
| 266 """Helper method for converting a type name to the proper | 137 """Helper method for converting a type name to the proper |
| 267 Dart name""" | 138 Dart name""" |
| 268 if self._IsPrimitiveType(type_name): | 139 if IsPrimitiveType(type_name): |
| 269 return self._ConvertPrimitiveType(type_name) | 140 return ConvertPrimitiveType(type_name) |
| 270 | 141 |
| 271 if self._IsDartType(type_name): | 142 if self._IsDartType(type_name): |
| 272 # This is for when dart qualified names are explicitly | 143 # This is for when dart qualified names are explicitly |
| 273 # defined in the IDLs. Just let them be. | 144 # defined in the IDLs. Just let them be. |
| 274 return type_name | 145 return type_name |
| 275 | 146 |
| 276 dart_template_match = self._dart_templates_re.match(type_name) | 147 dart_template_match = self._dart_templates_re.match(type_name) |
| 277 if dart_template_match: | 148 if dart_template_match: |
| 278 # Dart templates | 149 # Dart templates |
| 279 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] | 150 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 interface.parents = filter(HasAnnotations, interface.parents) | 213 interface.parents = filter(HasAnnotations, interface.parents) |
| 343 else: | 214 else: |
| 344 database.DeleteInterface(interface.id) | 215 database.DeleteInterface(interface.id) |
| 345 | 216 |
| 346 self.FilterMembersWithUnidentifiedTypes(database) | 217 self.FilterMembersWithUnidentifiedTypes(database) |
| 347 | 218 |
| 348 | 219 |
| 349 def Generate(self, database, output_dir, | 220 def Generate(self, database, output_dir, |
| 350 module_source_preference=[], source_filter=None, | 221 module_source_preference=[], source_filter=None, |
| 351 super_database=None, common_prefix=None, super_map={}, | 222 super_database=None, common_prefix=None, super_map={}, |
| 352 lib_dir=None, systems=[]): | 223 html_map={}, lib_dir=None, systems=[]): |
| 353 """Generates Dart and JS files for the loaded interfaces. | 224 """Generates Dart and JS files for the loaded interfaces. |
| 354 | 225 |
| 355 Args: | 226 Args: |
| 356 database -- database containing interfaces to generate code for. | 227 database -- database containing interfaces to generate code for. |
| 357 output_dir -- directory to write generated files to. | 228 output_dir -- directory to write generated files to. |
| 358 module_source_preference -- priority order list of source annotations to | 229 module_source_preference -- priority order list of source annotations to |
| 359 use when choosing a module name, if none specified uses the module name | 230 use when choosing a module name, if none specified uses the module name |
| 360 from the database. | 231 from the database. |
| 361 source_filter -- if specified, only outputs interfaces that have one of | 232 source_filter -- if specified, only outputs interfaces that have one of |
| 362 these source annotation and rewrites the names of superclasses not | 233 these source annotation and rewrites the names of superclasses not |
| 363 marked with this source to use the common prefix. | 234 marked with this source to use the common prefix. |
| 364 super_database -- database containing super interfaces that the generated | 235 super_database -- database containing super interfaces that the generated |
| 365 interfaces should extend. | 236 interfaces should extend. |
| 366 common_prefix -- prefix for the common library, if any. | 237 common_prefix -- prefix for the common library, if any. |
| 367 lib_file_path -- filename for generated .lib file, None if not required. | 238 lib_file_path -- filename for generated .lib file, None if not required. |
| 368 lib_template -- template file in this directory for generated lib file. | 239 lib_template -- template file in this directory for generated lib file. |
| 369 """ | 240 """ |
| 370 | 241 |
| 371 self._emitters = multiemitter.MultiEmitter() | 242 self._emitters = multiemitter.MultiEmitter() |
| 372 self._database = database | 243 self._database = database |
| 373 self._output_dir = output_dir | 244 self._output_dir = output_dir |
| 374 | 245 |
| 375 self._ComputeInheritanceClosure() | 246 self._ComputeInheritanceClosure() |
| 376 | 247 |
| 377 self._systems = [] | 248 self._systems = [] |
| 378 | 249 |
| 379 # TODO(jmesserly): only create these if needed | 250 # TODO(jmesserly): only create these if needed |
| 380 interface_system = InterfacesSystem( | 251 if ('htmlfrog' in systems) or ('htmldartium' in systems): |
| 381 TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), | 252 html_interface_system = HtmlInterfacesSystem( |
| 382 self._database, self._emitters, self._output_dir) | 253 TemplateLoader(self._template_dir, ['html/interface', 'html', '']), |
| 383 self._systems.append(interface_system) | 254 self._database, self._emitters, self._output_dir, self) |
| 384 | 255 self._systems.append(html_interface_system) |
| 385 html_interface_system = HtmlInterfacesSystem( | 256 else: |
| 386 TemplateLoader(self._template_dir, ['html/interface', 'html', '']), | 257 interface_system = InterfacesSystem( |
| 387 self._database, self._emitters, self._output_dir) | 258 TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), |
| 388 self._systems.append(html_interface_system) | 259 self._database, self._emitters, self._output_dir) |
| 260 self._systems.append(interface_system) |
| 389 | 261 |
| 390 if 'native' in systems: | 262 if 'native' in systems: |
| 391 native_system = NativeImplementationSystem( | 263 native_system = NativeImplementationSystem( |
| 392 TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), | 264 TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), |
| 393 self._database, self._emitters, self._auxiliary_dir, | 265 self._database, self._emitters, self._auxiliary_dir, |
| 394 self._output_dir) | 266 self._output_dir) |
| 395 | 267 |
| 396 self._systems.append(native_system) | 268 self._systems.append(native_system) |
| 397 | 269 |
| 398 if 'wrapping' in systems: | 270 if 'wrapping' in systems: |
| (...skipping 20 matching lines...) Expand all Loading... |
| 419 frog_system = FrogSystem( | 291 frog_system = FrogSystem( |
| 420 TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), | 292 TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), |
| 421 self._database, self._emitters, self._output_dir) | 293 self._database, self._emitters, self._output_dir) |
| 422 | 294 |
| 423 frog_system._interface_system = interface_system | 295 frog_system._interface_system = interface_system |
| 424 self._systems.append(frog_system) | 296 self._systems.append(frog_system) |
| 425 | 297 |
| 426 if 'htmlfrog' in systems: | 298 if 'htmlfrog' in systems: |
| 427 html_system = HtmlFrogSystem( | 299 html_system = HtmlFrogSystem( |
| 428 TemplateLoader(self._template_dir, ['html/frog', 'html', '']), | 300 TemplateLoader(self._template_dir, ['html/frog', 'html', '']), |
| 429 self._database, self._emitters, self._output_dir) | 301 self._database, self._emitters, self._output_dir, self) |
| 430 | 302 |
| 431 html_system._interface_system = html_interface_system | 303 html_system._interface_system = html_interface_system |
| 432 self._systems.append(html_system) | 304 self._systems.append(html_system) |
| 433 | 305 |
| 434 if 'htmldartium' in systems: | 306 if 'htmldartium' in systems: |
| 435 html_system = HtmlDartiumSystem( | 307 html_system = HtmlDartiumSystem( |
| 436 TemplateLoader(self._template_dir, ['html/dartium', 'html', '']), | 308 TemplateLoader(self._template_dir, ['html/dartium', 'html', '']), |
| 437 self._database, self._emitters, self._output_dir) | 309 self._database, self._emitters, self._output_dir, self) |
| 438 | 310 |
| 439 html_system._interface_system = html_interface_system | 311 html_system._interface_system = html_interface_system |
| 440 self._systems.append(html_system) | 312 self._systems.append(html_system) |
| 441 | 313 |
| 442 | |
| 443 # Collect interfaces | 314 # Collect interfaces |
| 444 interfaces = [] | 315 interfaces = [] |
| 445 for interface in database.GetInterfaces(): | 316 for interface in database.GetInterfaces(): |
| 446 if not _MatchSourceFilter(source_filter, interface): | 317 if not MatchSourceFilter(source_filter, interface): |
| 447 # Skip this interface since it's not present in the required source | 318 # Skip this interface since it's not present in the required source |
| 448 _logger.info('Omitting interface - %s' % interface.id) | 319 _logger.info('Omitting interface - %s' % interface.id) |
| 449 continue | 320 continue |
| 450 interfaces.append(interface) | 321 interfaces.append(interface) |
| 451 | 322 |
| 452 # TODO(sra): Use this list of exception names to generate information to | 323 # TODO(sra): Use this list of exception names to generate information to |
| 453 # tell Frog which exceptions can be passed from JS to Dart code. | 324 # tell Frog which exceptions can be passed from JS to Dart code. |
| 454 exceptions = self._CollectExceptions(interfaces) | 325 exceptions = self._CollectExceptions(interfaces) |
| 455 | 326 |
| 456 # Render all interfaces into Dart and save them in files. | 327 # Render all interfaces into Dart and save them in files. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 467 super_interface = super_name | 338 super_interface = super_name |
| 468 | 339 |
| 469 interface_name = interface.id | 340 interface_name = interface.id |
| 470 auxiliary_file = self._auxiliary_files.get(interface_name) | 341 auxiliary_file = self._auxiliary_files.get(interface_name) |
| 471 if auxiliary_file is not None: | 342 if auxiliary_file is not None: |
| 472 _logger.info('Skipping %s because %s exists' % ( | 343 _logger.info('Skipping %s because %s exists' % ( |
| 473 interface_name, auxiliary_file)) | 344 interface_name, auxiliary_file)) |
| 474 continue | 345 continue |
| 475 | 346 |
| 476 | 347 |
| 477 info = _RecognizeCallback(interface) | 348 info = RecognizeCallback(interface) |
| 478 if info: | 349 if info: |
| 479 for system in self._systems: | 350 for system in self._systems: |
| 480 system.ProcessCallback(interface, info) | 351 system.ProcessCallback(interface, info) |
| 481 else: | 352 else: |
| 482 if 'Callback' in interface.ext_attrs: | 353 if 'Callback' in interface.ext_attrs: |
| 483 _logger.info('Malformed callback: %s' % interface.id) | 354 _logger.info('Malformed callback: %s' % interface.id) |
| 484 self._ProcessInterface(interface, super_interface, | 355 self._ProcessInterface(interface, super_interface, |
| 485 source_filter, common_prefix) | 356 source_filter, common_prefix) |
| 486 | 357 |
| 487 # Libraries | 358 # Libraries |
| 488 if lib_dir: | 359 if lib_dir: |
| 489 for system in self._systems: | 360 for system in self._systems: |
| 490 system.GenerateLibraries(lib_dir) | 361 system.GenerateLibraries(lib_dir) |
| 491 | 362 |
| 492 for system in self._systems: | 363 for system in self._systems: |
| 493 system.Finish() | 364 system.Finish() |
| 494 | 365 |
| 495 | 366 |
| 496 def _PreOrderInterfaces(self, interfaces): | 367 def _PreOrderInterfaces(self, interfaces): |
| 497 """Returns the interfaces in pre-order, i.e. parents first.""" | 368 """Returns the interfaces in pre-order, i.e. parents first.""" |
| 498 seen = set() | 369 seen = set() |
| 499 ordered = [] | 370 ordered = [] |
| 500 def visit(interface): | 371 def visit(interface): |
| 501 if interface.id in seen: | 372 if interface.id in seen: |
| 502 return | 373 return |
| 503 seen.add(interface.id) | 374 seen.add(interface.id) |
| 504 for parent in interface.parents: | 375 for parent in interface.parents: |
| 505 if _IsDartCollectionType(parent.type.id): | 376 if IsDartCollectionType(parent.type.id): |
| 506 continue | 377 continue |
| 507 if self._database.HasInterface(parent.type.id): | 378 if self._database.HasInterface(parent.type.id): |
| 508 parent_interface = self._database.GetInterface(parent.type.id) | 379 parent_interface = self._database.GetInterface(parent.type.id) |
| 509 visit(parent_interface) | 380 visit(parent_interface) |
| 510 ordered.append(interface) | 381 ordered.append(interface) |
| 511 | 382 |
| 512 for interface in interfaces: | 383 for interface in interfaces: |
| 513 visit(interface) | 384 visit(interface) |
| 514 return ordered | 385 return ordered |
| 515 | 386 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 532 for const in sorted(interface.constants, ConstantOutputOrder): | 403 for const in sorted(interface.constants, ConstantOutputOrder): |
| 533 for generator in generators: | 404 for generator in generators: |
| 534 generator.AddConstant(const) | 405 generator.AddConstant(const) |
| 535 | 406 |
| 536 attributes = [attr for attr in interface.attributes | 407 attributes = [attr for attr in interface.attributes |
| 537 if not self._IsEventAttribute(interface, attr)] | 408 if not self._IsEventAttribute(interface, attr)] |
| 538 for (getter, setter) in _PairUpAttributes(attributes): | 409 for (getter, setter) in _PairUpAttributes(attributes): |
| 539 for generator in generators: | 410 for generator in generators: |
| 540 generator.AddAttribute(getter, setter) | 411 generator.AddAttribute(getter, setter) |
| 541 | 412 |
| 542 events = _PairUpAttributes([attr for attr in interface.attributes | 413 events = set([attr for attr in interface.attributes |
| 543 if self._IsEventAttribute(interface, attr)]) | 414 if self._IsEventAttribute(interface, attr)]) |
| 415 |
| 544 if events: | 416 if events: |
| 545 for generator in generators: | 417 for generator in generators: |
| 546 generator.AddEventAttributes(events) | 418 generator.AddEventAttributes(events) |
| 547 | 419 |
| 548 # The implementation should define an indexer if the interface directly | 420 # The implementation should define an indexer if the interface directly |
| 549 # extends List. | 421 # extends List. |
| 550 element_type = MaybeListElementType(interface) | 422 element_type = MaybeListElementType(interface) |
| 551 if element_type: | 423 if element_type: |
| 552 for generator in generators: | 424 for generator in generators: |
| 553 generator.AddIndexer(element_type) | 425 generator.AddIndexer(element_type) |
| 554 | |
| 555 # Group overloaded operations by id | 426 # Group overloaded operations by id |
| 556 operationsById = {} | 427 operationsById = {} |
| 557 for operation in interface.operations: | 428 for operation in interface.operations: |
| 558 if operation.id not in operationsById: | 429 if operation.id not in operationsById: |
| 559 operationsById[operation.id] = [] | 430 operationsById[operation.id] = [] |
| 560 operationsById[operation.id].append(operation) | 431 operationsById[operation.id].append(operation) |
| 561 | 432 |
| 562 # Generate operations | 433 # Generate operations |
| 563 for id in sorted(operationsById.keys()): | 434 for id in sorted(operationsById.keys()): |
| 564 operations = operationsById[id] | 435 operations = operationsById[id] |
| 565 info = _AnalyzeOperation(interface, operations) | 436 info = AnalyzeOperation(interface, operations) |
| 566 for generator in generators: | 437 for generator in generators: |
| 567 generator.AddOperation(info) | 438 generator.AddOperation(info) |
| 568 | 439 |
| 569 # With multiple inheritance, attributes and operations of non-first | 440 # With multiple inheritance, attributes and operations of non-first |
| 570 # interfaces need to be added. Sometimes the attribute or operation is | 441 # interfaces need to be added. Sometimes the attribute or operation is |
| 571 # defined in the current interface as well as a parent. In that case we | 442 # defined in the current interface as well as a parent. In that case we |
| 572 # avoid making a duplicate definition and pray that the signatures match. | 443 # avoid making a duplicate definition and pray that the signatures match. |
| 573 | 444 |
| 574 for parent_interface in self._TransitiveSecondaryParents(interface): | 445 for parent_interface in self._TransitiveSecondaryParents(interface): |
| 575 if isinstance(parent_interface, str): # _IsDartCollectionType(parent_inte
rface) | 446 if isinstance(parent_interface, str): # IsDartCollectionType(parent_inter
face) |
| 576 continue | 447 continue |
| 577 attributes = [attr for attr in parent_interface.attributes | 448 attributes = [attr for attr in parent_interface.attributes |
| 578 if not _FindMatchingAttribute(interface, attr)] | 449 if not FindMatchingAttribute(interface, attr)] |
| 579 for (getter, setter) in _PairUpAttributes(attributes): | 450 for (getter, setter) in _PairUpAttributes(attributes): |
| 580 for generator in generators: | 451 for generator in generators: |
| 581 generator.AddSecondaryAttribute(parent_interface, getter, setter) | 452 generator.AddSecondaryAttribute(parent_interface, getter, setter) |
| 582 | 453 |
| 583 # Group overloaded operations by id | 454 # Group overloaded operations by id |
| 584 operationsById = {} | 455 operationsById = {} |
| 585 for operation in parent_interface.operations: | 456 for operation in parent_interface.operations: |
| 586 if operation.id not in operationsById: | 457 if operation.id not in operationsById: |
| 587 operationsById[operation.id] = [] | 458 operationsById[operation.id] = [] |
| 588 operationsById[operation.id].append(operation) | 459 operationsById[operation.id].append(operation) |
| 589 | 460 |
| 590 # Generate operations | 461 # Generate operations |
| 591 for id in sorted(operationsById.keys()): | 462 for id in sorted(operationsById.keys()): |
| 592 if not any(op.id == id for op in interface.operations): | 463 if not any(op.id == id for op in interface.operations): |
| 593 operations = operationsById[id] | 464 operations = operationsById[id] |
| 594 info = _AnalyzeOperation(interface, operations) | 465 info = AnalyzeOperation(interface, operations) |
| 595 for generator in generators: | 466 for generator in generators: |
| 596 generator.AddSecondaryOperation(parent_interface, info) | 467 generator.AddSecondaryOperation(parent_interface, info) |
| 597 | 468 |
| 598 for generator in generators: | 469 for generator in generators: |
| 599 generator.FinishInterface() | 470 generator.FinishInterface() |
| 600 return | 471 return |
| 601 | 472 |
| 602 def _IsEventAttribute(self, interface, attr): | 473 def _IsEventAttribute(self, interface, attr): |
| 603 # Remove EventListener attributes like 'onclick' when addEventListener | 474 # Remove EventListener attributes like 'onclick' when addEventListener |
| 604 # is available. | 475 # is available. |
| 605 if attr.type.id == 'EventListener': | 476 return (attr.type.id == 'EventListener' and |
| 606 if 'EventTarget' in self._AllImplementedInterfaces(interface): | 477 'EventTarget' in self._AllImplementedInterfaces(interface)) |
| 607 return True | |
| 608 return False | |
| 609 | 478 |
| 610 def _TransitiveSecondaryParents(self, interface): | 479 def _TransitiveSecondaryParents(self, interface): |
| 611 """Returns a list of all non-primary parents. | 480 """Returns a list of all non-primary parents. |
| 612 | 481 |
| 613 The list contains the interface objects for interfaces defined in the | 482 The list contains the interface objects for interfaces defined in the |
| 614 database, and the name for undefined interfaces. | 483 database, and the name for undefined interfaces. |
| 615 """ | 484 """ |
| 616 def walk(parents): | 485 def walk(parents): |
| 617 for parent in parents: | 486 for parent in parents: |
| 618 if _IsDartCollectionType(parent.type.id): | 487 if IsDartCollectionType(parent.type.id): |
| 619 result.append(parent.type.id) | 488 result.append(parent.type.id) |
| 620 continue | 489 continue |
| 621 if self._database.HasInterface(parent.type.id): | 490 if self._database.HasInterface(parent.type.id): |
| 622 parent_interface = self._database.GetInterface(parent.type.id) | 491 parent_interface = self._database.GetInterface(parent.type.id) |
| 623 result.append(parent_interface) | 492 result.append(parent_interface) |
| 624 walk(parent_interface.parents) | 493 walk(parent_interface.parents) |
| 625 | 494 |
| 626 result = [] | 495 result = [] |
| 627 walk(interface.parents[1:]) | 496 walk(interface.parents[1:]) |
| 628 return result; | 497 return result; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 collected = [] | 540 collected = [] |
| 672 Collect(interface, seen, collected) | 541 Collect(interface, seen, collected) |
| 673 self._inheritance_closure[interface.id] = collected | 542 self._inheritance_closure[interface.id] = collected |
| 674 | 543 |
| 675 def _AllImplementedInterfaces(self, interface): | 544 def _AllImplementedInterfaces(self, interface): |
| 676 """Returns a list of the names of all interfaces implemented by 'interface'. | 545 """Returns a list of the names of all interfaces implemented by 'interface'. |
| 677 List includes the name of 'interface'. | 546 List includes the name of 'interface'. |
| 678 """ | 547 """ |
| 679 return self._inheritance_closure[interface.id] | 548 return self._inheritance_closure[interface.id] |
| 680 | 549 |
| 681 | |
| 682 def _RecognizeCallback(interface): | |
| 683 """Returns the info for the callback method if the interface smells like a | |
| 684 callback. | |
| 685 """ | |
| 686 if 'Callback' not in interface.ext_attrs: return None | |
| 687 handlers = [op for op in interface.operations if op.id == 'handleEvent'] | |
| 688 if not handlers: return None | |
| 689 if not (handlers == interface.operations): return None | |
| 690 return _AnalyzeOperation(interface, handlers) | |
| 691 | |
| 692 | |
| 693 def _PairUpAttributes(attributes): | 550 def _PairUpAttributes(attributes): |
| 694 """Returns a list of (getter, setter) pairs sorted by name. | 551 """Returns a list of (getter, setter) pairs sorted by name. |
| 695 | 552 |
| 696 One element of the pair may be None. | 553 One element of the pair may be None. |
| 697 """ | 554 """ |
| 698 names = sorted(set(attr.id for attr in attributes)) | 555 names = sorted(set(attr.id for attr in attributes)) |
| 699 getters = {} | 556 getters = {} |
| 700 setters = {} | 557 setters = {} |
| 701 for attr in attributes: | 558 for attr in attributes: |
| 702 if attr.is_fc_getter: | 559 if attr.is_fc_getter: |
| 703 getters[attr.id] = attr | 560 getters[attr.id] = attr |
| 704 elif attr.is_fc_setter: | 561 elif attr.is_fc_setter: |
| 705 setters[attr.id] = attr | 562 setters[attr.id] = attr |
| 706 return [(getters.get(id), setters.get(id)) for id in names] | 563 return [(getters.get(id), setters.get(id)) for id in names] |
| 707 | 564 |
| 708 | |
| 709 def _FindMatchingAttribute(interface, attr1): | |
| 710 matches = [attr2 for attr2 in interface.attributes | |
| 711 if attr1.id == attr2.id | |
| 712 and attr1.is_fc_getter == attr2.is_fc_getter | |
| 713 and attr1.is_fc_setter == attr2.is_fc_setter] | |
| 714 if matches: | |
| 715 assert len(matches) == 1 | |
| 716 return matches[0] | |
| 717 return None | |
| 718 | |
| 719 | |
| 720 def _AnalyzeOperation(interface, operations): | |
| 721 """Makes operation calling convention decision for a set of overloads. | |
| 722 | |
| 723 Returns: An OperationInfo object. | |
| 724 """ | |
| 725 | |
| 726 # Zip together arguments from each overload by position, then convert | |
| 727 # to a dart argument. | |
| 728 | |
| 729 # Given a list of overloaded arguments, choose a suitable name. | |
| 730 def OverloadedName(args): | |
| 731 return '_OR_'.join(sorted(set(arg.id for arg in args))) | |
| 732 | |
| 733 # Given a list of overloaded arguments, choose a suitable type. | |
| 734 def OverloadedType(args): | |
| 735 typeIds = sorted(set(arg.type.id for arg in args)) | |
| 736 if len(typeIds) == 1: | |
| 737 return typeIds[0] | |
| 738 else: | |
| 739 return TypeName(typeIds, interface) | |
| 740 | |
| 741 # Given a list of overloaded arguments, render a dart argument. | |
| 742 def DartArg(args): | |
| 743 filtered = filter(None, args) | |
| 744 optional = any(not arg or arg.is_optional for arg in args) | |
| 745 type = OverloadedType(filtered) | |
| 746 name = OverloadedName(filtered) | |
| 747 if optional: | |
| 748 return (name, type, 'null') | |
| 749 else: | |
| 750 return (name, type, None) | |
| 751 | |
| 752 args = map(lambda *args: DartArg(args), | |
| 753 *(op.arguments for op in operations)) | |
| 754 | |
| 755 info = OperationInfo() | |
| 756 info.overloads = operations | |
| 757 info.declared_name = operations[0].id | |
| 758 info.name = operations[0].ext_attrs.get('DartName', info.declared_name) | |
| 759 info.js_name = info.declared_name | |
| 760 info.type_name = operations[0].type.id # TODO: widen. | |
| 761 info.arg_infos = args | |
| 762 return info | |
| 763 | |
| 764 | |
| 765 class OperationInfo(object): | |
| 766 """Holder for various derived information from a set of overloaded operations. | |
| 767 | |
| 768 Attributes: | |
| 769 overloads: A list of IDL operation overloads with the same name. | |
| 770 name: A string, the simple name of the operation. | |
| 771 type_name: A string, the name of the return type of the operation. | |
| 772 arg_infos: A list of (name, type, default_value) tuples. | |
| 773 default_value is None for mandatory arguments. | |
| 774 """ | |
| 775 | |
| 776 def ParametersInterfaceDeclaration(self): | |
| 777 """Returns a formatted string declaring the parameters for the interface.""" | |
| 778 return self._FormatArgs(self.arg_infos, True) | |
| 779 | |
| 780 def ParametersImplementationDeclaration(self, rename_type=None): | |
| 781 """Returns a formatted string declaring the parameters for the | |
| 782 implementation. | |
| 783 | |
| 784 Args: | |
| 785 rename_type: A function that allows the types to be renamed. | |
| 786 """ | |
| 787 args = self.arg_infos | |
| 788 if rename_type: | |
| 789 args = [(name, rename_type(type), default) | |
| 790 for (name, type, default) in args] | |
| 791 return self._FormatArgs(args, False) | |
| 792 | |
| 793 | |
| 794 def _FormatArgs(self, args, is_interface): | |
| 795 def FormatArg(arg_info): | |
| 796 """Returns an argument declaration fragment for an argument info tuple.""" | |
| 797 (name, type, default) = arg_info | |
| 798 if default: | |
| 799 return '%s %s = %s' % (type, name, default) | |
| 800 else: | |
| 801 return '%s %s' % (type, name) | |
| 802 | |
| 803 required = [] | |
| 804 optional = [] | |
| 805 for (name, type, default) in args: | |
| 806 if default: | |
| 807 if is_interface: | |
| 808 optional.append((name, type, None)) # Default values illegal. | |
| 809 else: | |
| 810 optional.append((name, type, default)) | |
| 811 else: | |
| 812 if optional: | |
| 813 raise Exception('Optional arguments cannot precede required ones: ' | |
| 814 + str(args)) | |
| 815 required.append((name, type, None)) | |
| 816 argtexts = map(FormatArg, required) | |
| 817 if optional: | |
| 818 argtexts.append('[' + ', '.join(map(FormatArg, optional)) + ']') | |
| 819 return ', '.join(argtexts) | |
| 820 | |
| 821 | |
| 822 def MaybeListElementTypeName(type_name): | |
| 823 """Returns the List element type T from string of form "List<T>", or None.""" | |
| 824 match = re.match(r'List<(\w*)>$', type_name) | |
| 825 if match: | |
| 826 return match.group(1) | |
| 827 return None | |
| 828 | |
| 829 def MaybeListElementType(interface): | |
| 830 """Returns the List element type T, or None in interface does not implement | |
| 831 List<T>. | |
| 832 """ | |
| 833 for parent in interface.parents: | |
| 834 element_type = MaybeListElementTypeName(parent.type.id) | |
| 835 if element_type: | |
| 836 return element_type | |
| 837 return None | |
| 838 | |
| 839 def MaybeTypedArrayElementType(interface): | |
| 840 """Returns the typed array element type, or None in interface is not a | |
| 841 TypedArray. | |
| 842 """ | |
| 843 # Typed arrays implement ArrayBufferView and List<T>. | |
| 844 for parent in interface.parents: | |
| 845 if parent.type.id == 'ArrayBufferView': | |
| 846 return MaybeListElementType(interface) | |
| 847 if parent.type.id == 'Uint8Array': | |
| 848 return 'int' | |
| 849 return None | |
| 850 | |
| 851 | |
| 852 def AttributeOutputOrder(a, b): | |
| 853 """Canonical output ordering for attributes.""" | |
| 854 # Getters before setters: | |
| 855 if a.id < b.id: return -1 | |
| 856 if a.id > b.id: return 1 | |
| 857 if a.is_fc_setter < b.is_fc_setter: return -1 | |
| 858 if a.is_fc_setter > b.is_fc_setter: return 1 | |
| 859 return 0 | |
| 860 | |
| 861 def ConstantOutputOrder(a, b): | |
| 862 """Canonical output ordering for constants.""" | |
| 863 if a.id < b.id: return -1 | |
| 864 if a.id > b.id: return 1 | |
| 865 return 0 | |
| 866 | |
| 867 | |
| 868 def _FormatNameList(names): | |
| 869 """Returns JavaScript array literal expression with one name per line.""" | |
| 870 #names = sorted(names) | |
| 871 if len(names) <= 1: | |
| 872 expression_string = str(names) # e.g. ['length'] | |
| 873 else: | |
| 874 expression_string = ',\n '.join(str(names).split(',')) | |
| 875 expression_string = expression_string.replace('[', '[\n ') | |
| 876 return expression_string | |
| 877 | |
| 878 | |
| 879 def IndentText(text, indent): | |
| 880 """Format lines of text with indent.""" | |
| 881 def FormatLine(line): | |
| 882 if line.strip(): | |
| 883 return '%s%s\n' % (indent, line) | |
| 884 else: | |
| 885 return '\n' | |
| 886 return ''.join(FormatLine(line) for line in text.split('\n')) | |
| 887 | |
| 888 # ------------------------------------------------------------------------------ | 565 # ------------------------------------------------------------------------------ |
| 889 | 566 |
| 890 class TemplateLoader(object): | 567 class TemplateLoader(object): |
| 891 """Loads template files from a path.""" | 568 """Loads template files from a path.""" |
| 892 | 569 |
| 893 def __init__(self, root, subpaths): | 570 def __init__(self, root, subpaths): |
| 894 """Initializes loader. | 571 """Initializes loader. |
| 895 | 572 |
| 896 Args: | 573 Args: |
| 897 root - a string, the directory under which the templates are stored. | 574 root - a string, the directory under which the templates are stored. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 916 return None | 593 return None |
| 917 | 594 |
| 918 def Load(self, name): | 595 def Load(self, name): |
| 919 """Returns contents of template file as a string, or raises an exception.""" | 596 """Returns contents of template file as a string, or raises an exception.""" |
| 920 template = self.TryLoad(name) | 597 template = self.TryLoad(name) |
| 921 if template is not None: # Can be empty string | 598 if template is not None: # Can be empty string |
| 922 return template | 599 return template |
| 923 raise Exception("Could not find template '%s' on %s / %s" % ( | 600 raise Exception("Could not find template '%s' on %s / %s" % ( |
| 924 name, self._root, self._subpaths)) | 601 name, self._root, self._subpaths)) |
| 925 | 602 |
| 926 | |
| 927 # ------------------------------------------------------------------------------ | |
| 928 | |
| 929 class System(object): | |
| 930 """Generates all the files for one implementation.""" | |
| 931 | |
| 932 def __init__(self, templates, database, emitters, output_dir): | |
| 933 self._templates = templates | |
| 934 self._database = database | |
| 935 self._emitters = emitters | |
| 936 self._output_dir = output_dir | |
| 937 self._dart_callback_file_paths = [] | |
| 938 | |
| 939 def InterfaceGenerator(self, | |
| 940 interface, | |
| 941 common_prefix, | |
| 942 super_interface_name, | |
| 943 source_filter): | |
| 944 """Returns an interface generator for |interface|.""" | |
| 945 return None | |
| 946 | |
| 947 def ProcessCallback(self, interface, info): | |
| 948 pass | |
| 949 | |
| 950 def GenerateLibraries(self, lib_dir): | |
| 951 pass | |
| 952 | |
| 953 def Finish(self): | |
| 954 pass | |
| 955 | |
| 956 | |
| 957 def _ProcessCallback(self, interface, info, file_path): | |
| 958 """Generates a typedef for the callback interface.""" | |
| 959 self._dart_callback_file_paths.append(file_path) | |
| 960 code = self._emitters.FileEmitter(file_path) | |
| 961 | |
| 962 code.Emit(self._templates.Load('callback.darttemplate')) | |
| 963 code.Emit('typedef $TYPE $NAME($PARAMS);\n', | |
| 964 NAME=interface.id, | |
| 965 TYPE=info.type_name, | |
| 966 PARAMS=info.ParametersImplementationDeclaration()) | |
| 967 | |
| 968 def _GenerateLibFile(self, lib_template, lib_file_path, file_paths, | |
| 969 **template_args): | |
| 970 """Generates a lib file from a template and a list of files. | |
| 971 | |
| 972 Additional keyword arguments are passed to the template. | |
| 973 """ | |
| 974 # Load template. | |
| 975 template = self._templates.Load(lib_template) | |
| 976 # Generate the .lib file. | |
| 977 lib_file_contents = self._emitters.FileEmitter(lib_file_path) | |
| 978 | |
| 979 # Emit the list of #source directives. | |
| 980 list_emitter = lib_file_contents.Emit(template, **template_args) | |
| 981 lib_file_dir = os.path.dirname(lib_file_path) | |
| 982 for path in sorted(file_paths): | |
| 983 relpath = os.path.relpath(path, lib_file_dir) | |
| 984 list_emitter.Emit("#source('$PATH');\n", PATH=relpath) | |
| 985 | |
| 986 | |
| 987 def _BaseDefines(self, interface): | |
| 988 """Returns a set of names (strings) for members defined in a base class. | |
| 989 """ | |
| 990 def WalkParentChain(interface): | |
| 991 if interface.parents: | |
| 992 # Only consider primary parent, secondary parents are not on the | |
| 993 # implementation class inheritance chain. | |
| 994 parent = interface.parents[0] | |
| 995 if _IsDartCollectionType(parent.type.id): | |
| 996 return | |
| 997 if self._database.HasInterface(parent.type.id): | |
| 998 parent_interface = self._database.GetInterface(parent.type.id) | |
| 999 for attr in parent_interface.attributes: | |
| 1000 result.add(attr.id) | |
| 1001 for op in parent_interface.operations: | |
| 1002 result.add(op.id) | |
| 1003 WalkParentChain(parent_interface) | |
| 1004 | |
| 1005 result = set() | |
| 1006 WalkParentChain(interface) | |
| 1007 return result; | |
| 1008 | |
| 1009 | |
| 1010 # ------------------------------------------------------------------------------ | |
| 1011 | |
| 1012 class InterfacesSystem(System): | |
| 1013 | |
| 1014 def __init__(self, templates, database, emitters, output_dir): | |
| 1015 super(InterfacesSystem, self).__init__( | |
| 1016 templates, database, emitters, output_dir) | |
| 1017 self._dart_interface_file_paths = [] | |
| 1018 | |
| 1019 | |
| 1020 def InterfaceGenerator(self, | |
| 1021 interface, | |
| 1022 common_prefix, | |
| 1023 super_interface_name, | |
| 1024 source_filter): | |
| 1025 """.""" | |
| 1026 interface_name = interface.id | |
| 1027 dart_interface_file_path = self._FilePathForDartInterface(interface_name) | |
| 1028 | |
| 1029 self._dart_interface_file_paths.append(dart_interface_file_path) | |
| 1030 | |
| 1031 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) | |
| 1032 | |
| 1033 template_file = 'interface_%s.darttemplate' % interface_name | |
| 1034 template = self._templates.TryLoad(template_file) | |
| 1035 if not template: | |
| 1036 template = self._templates.Load('interface.darttemplate') | |
| 1037 | |
| 1038 return DartInterfaceGenerator( | |
| 1039 interface, dart_interface_code, | |
| 1040 template, | |
| 1041 common_prefix, super_interface_name, | |
| 1042 source_filter) | |
| 1043 | |
| 1044 def ProcessCallback(self, interface, info): | |
| 1045 """Generates a typedef for the callback interface.""" | |
| 1046 interface_name = interface.id | |
| 1047 file_path = self._FilePathForDartInterface(interface_name) | |
| 1048 self._ProcessCallback(interface, info, file_path) | |
| 1049 | |
| 1050 def GenerateLibraries(self, lib_dir): | |
| 1051 pass | |
| 1052 | |
| 1053 | |
| 1054 def _FilePathForDartInterface(self, interface_name): | |
| 1055 """Returns the file path of the Dart interface definition.""" | |
| 1056 return os.path.join(self._output_dir, 'src', 'interface', | |
| 1057 '%s.dart' % interface_name) | |
| 1058 | |
| 1059 | |
| 1060 # ------------------------------------------------------------------------------ | |
| 1061 | |
| 1062 class HtmlInterfacesSystem(System): | |
| 1063 | |
| 1064 def __init__(self, templates, database, emitters, output_dir): | |
| 1065 super(HtmlInterfacesSystem, self).__init__( | |
| 1066 templates, database, emitters, output_dir) | |
| 1067 self._dart_interface_file_paths = [] | |
| 1068 | |
| 1069 def InterfaceGenerator(self, | |
| 1070 interface, | |
| 1071 common_prefix, | |
| 1072 super_interface_name, | |
| 1073 source_filter): | |
| 1074 """.""" | |
| 1075 interface_name = interface.id | |
| 1076 dart_interface_file_path = self._FilePathForDartInterface(interface_name) | |
| 1077 | |
| 1078 self._dart_interface_file_paths.append(dart_interface_file_path) | |
| 1079 | |
| 1080 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) | |
| 1081 | |
| 1082 template_file = 'interface_%s.darttemplate' % interface_name | |
| 1083 template = self._templates.TryLoad(template_file) | |
| 1084 if not template: | |
| 1085 template = self._templates.Load('interface.darttemplate') | |
| 1086 | |
| 1087 return HtmlDartInterfaceGenerator( | |
| 1088 interface, dart_interface_code, | |
| 1089 template, | |
| 1090 common_prefix, super_interface_name, | |
| 1091 source_filter) | |
| 1092 | |
| 1093 def ProcessCallback(self, interface, info): | |
| 1094 """Generates a typedef for the callback interface.""" | |
| 1095 interface_name = interface.id | |
| 1096 file_path = self._FilePathForDartInterface(interface_name) | |
| 1097 self._ProcessCallback(interface, info, file_path) | |
| 1098 | |
| 1099 def GenerateLibraries(self, lib_dir): | |
| 1100 pass | |
| 1101 | |
| 1102 | |
| 1103 def _FilePathForDartInterface(self, interface_name): | |
| 1104 """Returns the file path of the Dart interface definition.""" | |
| 1105 # TODO(jmesserly): is this the right path | |
| 1106 return os.path.join(self._output_dir, 'html', 'interface', | |
| 1107 '%s.dart' % interface_name) | |
| 1108 | |
| 1109 | |
| 1110 # ------------------------------------------------------------------------------ | 603 # ------------------------------------------------------------------------------ |
| 1111 | 604 |
| 1112 class DummyImplementationSystem(System): | 605 class DummyImplementationSystem(System): |
| 1113 """Generates a dummy implementation for use by the editor analysis. | 606 """Generates a dummy implementation for use by the editor analysis. |
| 1114 | 607 |
| 1115 All the code comes from hand-written library files. | 608 All the code comes from hand-written library files. |
| 1116 """ | 609 """ |
| 1117 | 610 |
| 1118 def __init__(self, templates, database, emitters, output_dir): | 611 def __init__(self, templates, database, emitters, output_dir): |
| 1119 super(DummyImplementationSystem, self).__init__( | 612 super(DummyImplementationSystem, self).__init__( |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1192 pass | 685 pass |
| 1193 | 686 |
| 1194 | 687 |
| 1195 def _FilePathForDartWrappingImpl(self, interface_name): | 688 def _FilePathForDartWrappingImpl(self, interface_name): |
| 1196 """Returns the file path of the Dart wrapping implementation.""" | 689 """Returns the file path of the Dart wrapping implementation.""" |
| 1197 return os.path.join(self._output_dir, 'src', 'wrapping', | 690 return os.path.join(self._output_dir, 'src', 'wrapping', |
| 1198 '_%sWrappingImplementation.dart' % interface_name) | 691 '_%sWrappingImplementation.dart' % interface_name) |
| 1199 | 692 |
| 1200 # ------------------------------------------------------------------------------ | 693 # ------------------------------------------------------------------------------ |
| 1201 | 694 |
| 1202 class FrogSystem(System): | |
| 1203 | |
| 1204 def __init__(self, templates, database, emitters, output_dir): | |
| 1205 super(FrogSystem, self).__init__( | |
| 1206 templates, database, emitters, output_dir) | |
| 1207 self._dart_frog_file_paths = [] | |
| 1208 | |
| 1209 def InterfaceGenerator(self, | |
| 1210 interface, | |
| 1211 common_prefix, | |
| 1212 super_interface_name, | |
| 1213 source_filter): | |
| 1214 """.""" | |
| 1215 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) | |
| 1216 self._dart_frog_file_paths.append(dart_frog_file_path) | |
| 1217 | |
| 1218 template_file = 'impl_%s.darttemplate' % interface.id | |
| 1219 template = self._templates.TryLoad(template_file) | |
| 1220 if not template: | |
| 1221 template = self._templates.Load('frog_impl.darttemplate') | |
| 1222 | |
| 1223 dart_code = self._emitters.FileEmitter(dart_frog_file_path) | |
| 1224 return FrogInterfaceGenerator(self, interface, template, | |
| 1225 super_interface_name, dart_code) | |
| 1226 | |
| 1227 def GenerateLibraries(self, lib_dir): | |
| 1228 self._GenerateLibFile( | |
| 1229 'frog_dom.darttemplate', | |
| 1230 os.path.join(lib_dir, 'dom_frog.dart'), | |
| 1231 (self._interface_system._dart_interface_file_paths + | |
| 1232 self._interface_system._dart_callback_file_paths + | |
| 1233 self._dart_frog_file_paths)) | |
| 1234 | |
| 1235 def Finish(self): | |
| 1236 pass | |
| 1237 | |
| 1238 def _FilePathForFrogImpl(self, interface_name): | |
| 1239 """Returns the file path of the Frog implementation.""" | |
| 1240 return os.path.join(self._output_dir, 'src', 'frog', | |
| 1241 '%s.dart' % interface_name) | |
| 1242 | |
| 1243 | |
| 1244 # ------------------------------------------------------------------------------ | |
| 1245 | |
| 1246 class HtmlFrogSystem(System): | |
| 1247 | |
| 1248 def __init__(self, templates, database, emitters, output_dir): | |
| 1249 super(HtmlFrogSystem, self).__init__( | |
| 1250 templates, database, emitters, output_dir) | |
| 1251 self._dart_frog_file_paths = [] | |
| 1252 | |
| 1253 def InterfaceGenerator(self, | |
| 1254 interface, | |
| 1255 common_prefix, | |
| 1256 super_interface_name, | |
| 1257 source_filter): | |
| 1258 """.""" | |
| 1259 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) | |
| 1260 self._dart_frog_file_paths.append(dart_frog_file_path) | |
| 1261 | |
| 1262 template_file = 'impl_%s.darttemplate' % interface.id | |
| 1263 template = self._templates.TryLoad(template_file) | |
| 1264 if not template: | |
| 1265 template = self._templates.Load('frog_impl.darttemplate') | |
| 1266 | |
| 1267 dart_code = self._emitters.FileEmitter(dart_frog_file_path) | |
| 1268 return HtmlFrogInterfaceGenerator(self, interface, template, | |
| 1269 super_interface_name, dart_code) | |
| 1270 | |
| 1271 def GenerateLibraries(self, lib_dir): | |
| 1272 self._GenerateLibFile( | |
| 1273 'html_frog.darttemplate', | |
| 1274 os.path.join(lib_dir, 'html_frog.dart'), | |
| 1275 (self._interface_system._dart_interface_file_paths + | |
| 1276 self._interface_system._dart_callback_file_paths + | |
| 1277 self._dart_frog_file_paths)) | |
| 1278 | |
| 1279 def Finish(self): | |
| 1280 pass | |
| 1281 | |
| 1282 def _FilePathForFrogImpl(self, interface_name): | |
| 1283 """Returns the file path of the Frog implementation.""" | |
| 1284 # TODO(jmesserly): is this the right path | |
| 1285 return os.path.join(self._output_dir, 'html', 'frog', | |
| 1286 '%s.dart' % interface_name) | |
| 1287 | |
| 1288 # ------------------------------------------------------------------------------ | |
| 1289 | |
| 1290 class DartInterfaceGenerator(object): | |
| 1291 """Generates Dart Interface definition for one DOM IDL interface.""" | |
| 1292 | |
| 1293 def __init__(self, interface, emitter, template, | |
| 1294 common_prefix, super_interface, source_filter): | |
| 1295 """Generates Dart code for the given interface. | |
| 1296 | |
| 1297 Args: | |
| 1298 interface -- an IDLInterface instance. It is assumed that all types have | |
| 1299 been converted to Dart types (e.g. int, String), unless they are in the | |
| 1300 same package as the interface. | |
| 1301 common_prefix -- the prefix for the common library, if any. | |
| 1302 super_interface -- the name of the common interface that this interface | |
| 1303 implements, if any. | |
| 1304 source_filter -- if specified, rewrites the names of any superinterfaces | |
| 1305 that are not from these sources to use the common prefix. | |
| 1306 """ | |
| 1307 self._interface = interface | |
| 1308 self._emitter = emitter | |
| 1309 self._template = template | |
| 1310 self._common_prefix = common_prefix | |
| 1311 self._super_interface = super_interface | |
| 1312 self._source_filter = source_filter | |
| 1313 | |
| 1314 | |
| 1315 def StartInterface(self): | |
| 1316 if self._super_interface: | |
| 1317 typename = self._super_interface | |
| 1318 else: | |
| 1319 typename = self._interface.id | |
| 1320 | |
| 1321 # TODO(vsm): Add appropriate package / namespace syntax. | |
| 1322 (extends_emitter, | |
| 1323 self._members_emitter, | |
| 1324 self._top_level_emitter) = self._emitter.Emit( | |
| 1325 self._template + '$!TOP_LEVEL', | |
| 1326 ID=typename) | |
| 1327 | |
| 1328 extends = [] | |
| 1329 suppressed_extends = [] | |
| 1330 | |
| 1331 for parent in self._interface.parents: | |
| 1332 # TODO(vsm): Remove source_filter. | |
| 1333 if _MatchSourceFilter(self._source_filter, parent): | |
| 1334 # Parent is a DOM type. | |
| 1335 extends.append(parent.type.id) | |
| 1336 elif '<' in parent.type.id: | |
| 1337 # Parent is a Dart collection type. | |
| 1338 # TODO(vsm): Make this check more robust. | |
| 1339 extends.append(parent.type.id) | |
| 1340 else: | |
| 1341 suppressed_extends.append('%s.%s' % | |
| 1342 (self._common_prefix, parent.type.id)) | |
| 1343 | |
| 1344 comment = ' extends' | |
| 1345 if extends: | |
| 1346 extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) | |
| 1347 comment = ',' | |
| 1348 if suppressed_extends: | |
| 1349 extends_emitter.Emit(' /*$COMMENT $SUPERS */', | |
| 1350 COMMENT=comment, | |
| 1351 SUPERS=', '.join(suppressed_extends)) | |
| 1352 | |
| 1353 if typename in _interface_factories: | |
| 1354 extends_emitter.Emit(' default $F', F=_interface_factories[typename]) | |
| 1355 | |
| 1356 element_type = MaybeTypedArrayElementType(self._interface) | |
| 1357 if element_type: | |
| 1358 self._members_emitter.Emit( | |
| 1359 '\n' | |
| 1360 ' $CTOR(int length);\n' | |
| 1361 '\n' | |
| 1362 ' $CTOR.fromList(List<$TYPE> list);\n' | |
| 1363 '\n' | |
| 1364 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n', | |
| 1365 CTOR=self._interface.id, | |
| 1366 TYPE=element_type) | |
| 1367 | |
| 1368 | |
| 1369 def FinishInterface(self): | |
| 1370 # TODO(vsm): Use typedef if / when that is supported in Dart. | |
| 1371 # Define variant as subtype. | |
| 1372 if (self._super_interface and | |
| 1373 self._interface.id is not self._super_interface): | |
| 1374 consts_emitter = self._top_level_emitter.Emit( | |
| 1375 '\n' | |
| 1376 'interface $NAME extends $BASE {\n' | |
| 1377 '$!CONSTS' | |
| 1378 '}\n', | |
| 1379 NAME=self._interface.id, | |
| 1380 BASE=self._super_interface) | |
| 1381 for const in sorted(self._interface.constants, ConstantOutputOrder): | |
| 1382 self._EmitConstant(consts_emitter, const) | |
| 1383 | |
| 1384 def AddConstant(self, constant): | |
| 1385 if (not self._super_interface or | |
| 1386 self._interface.id is self._super_interface): | |
| 1387 self._EmitConstant(self._members_emitter, constant) | |
| 1388 | |
| 1389 def _EmitConstant(self, emitter, constant): | |
| 1390 emitter.Emit('\n static final $TYPE $NAME = $VALUE;\n', | |
| 1391 NAME=constant.id, | |
| 1392 TYPE=constant.type.id, | |
| 1393 VALUE=constant.value) | |
| 1394 | |
| 1395 def AddAttribute(self, getter, setter): | |
| 1396 if getter and setter and getter.type.id == setter.type.id: | |
| 1397 self._members_emitter.Emit('\n $TYPE $NAME;\n', | |
| 1398 NAME=getter.id, TYPE=getter.type.id); | |
| 1399 return | |
| 1400 if getter and not setter: | |
| 1401 self._members_emitter.Emit('\n final $TYPE $NAME;\n', | |
| 1402 NAME=getter.id, TYPE=getter.type.id); | |
| 1403 return | |
| 1404 raise Exception('Unexpected getter/setter combination %s %s' % | |
| 1405 (getter, setter)) | |
| 1406 | |
| 1407 def AddIndexer(self, element_type): | |
| 1408 # Interface inherits all operations from List<element_type>. | |
| 1409 pass | |
| 1410 | |
| 1411 def AddOperation(self, info): | |
| 1412 """ | |
| 1413 Arguments: | |
| 1414 operations - contains the overloads, one or more operations with the same | |
| 1415 name. | |
| 1416 """ | |
| 1417 self._members_emitter.Emit('\n' | |
| 1418 ' $TYPE $NAME($PARAMS);\n', | |
| 1419 TYPE=info.type_name, | |
| 1420 NAME=info.name, | |
| 1421 PARAMS=info.ParametersInterfaceDeclaration()) | |
| 1422 | |
| 1423 # Interfaces get secondary members directly via the superinterfaces. | |
| 1424 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 1425 pass | |
| 1426 | |
| 1427 def AddSecondaryOperation(self, interface, attr): | |
| 1428 pass | |
| 1429 | |
| 1430 def AddEventAttributes(self, event_attrs): | |
| 1431 pass | |
| 1432 | |
| 1433 # Given a sorted sequence of type identifiers, return an appropriate type | |
| 1434 # name | |
| 1435 def TypeName(typeIds, interface): | |
| 1436 # Dynamically type this field for now. | |
| 1437 return 'var' | |
| 1438 | |
| 1439 # ------------------------------------------------------------------------------ | |
| 1440 | |
| 1441 # TODO(jmesserly): inheritance is probably not the right way to factor this long | |
| 1442 # term, but it makes merging better for now. | |
| 1443 class HtmlDartInterfaceGenerator(DartInterfaceGenerator): | |
| 1444 """Generates Dart Interface definition for one DOM IDL interface.""" | |
| 1445 | |
| 1446 def __init__(self, interface, emitter, template, | |
| 1447 common_prefix, super_interface, source_filter): | |
| 1448 super(HtmlDartInterfaceGenerator, self).__init__(interface, | |
| 1449 emitter, template, common_prefix, super_interface, source_filter) | |
| 1450 | |
| 1451 def AddEventAttributes(self, event_attrs): | |
| 1452 events_interface = self._interface.id + 'Events' | |
| 1453 self._members_emitter.Emit('\n $TYPE get on();\n', | |
| 1454 TYPE=events_interface) | |
| 1455 events_members = self._emitter.Emit( | |
| 1456 '\ninterface $INTERFACE {\n$!MEMBERS}\n', | |
| 1457 INTERFACE=events_interface) | |
| 1458 | |
| 1459 for getter, setter in event_attrs: | |
| 1460 event = getter or setter | |
| 1461 events_members.Emit('\n EventListenerList get $NAME();\n', NAME=event.id) | |
| 1462 | |
| 1463 | |
| 1464 # ------------------------------------------------------------------------------ | |
| 1465 | |
| 1466 class DummyInterfaceGenerator(object): | |
| 1467 """Generates nothing.""" | |
| 1468 | |
| 1469 def __init__(self, system, interface): | |
| 1470 pass | |
| 1471 | |
| 1472 def StartInterface(self): | |
| 1473 pass | |
| 1474 | |
| 1475 def FinishInterface(self): | |
| 1476 pass | |
| 1477 | |
| 1478 def AddConstant(self, constant): | |
| 1479 pass | |
| 1480 | |
| 1481 def AddAttribute(self, getter, setter): | |
| 1482 pass | |
| 1483 | |
| 1484 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 1485 pass | |
| 1486 | |
| 1487 def AddSecondaryOperation(self, interface, info): | |
| 1488 pass | |
| 1489 | |
| 1490 def AddIndexer(self, element_type): | |
| 1491 pass | |
| 1492 | |
| 1493 def AddTypedArrayConstructors(self, element_type): | |
| 1494 pass | |
| 1495 | |
| 1496 def AddOperation(self, info): | |
| 1497 pass | |
| 1498 | |
| 1499 def AddEventAttributes(self, event_attrs): | |
| 1500 pass | |
| 1501 | |
| 1502 # ------------------------------------------------------------------------------ | |
| 1503 | |
| 1504 class WrappingInterfaceGenerator(object): | |
| 1505 """Generates Dart and JS implementation for one DOM IDL interface.""" | |
| 1506 | |
| 1507 def __init__(self, interface, super_interface, dart_code, base_members): | |
| 1508 """Generates Dart and JS code for the given interface. | |
| 1509 | |
| 1510 Args: | |
| 1511 | |
| 1512 interface: an IDLInterface instance. It is assumed that all types have | |
| 1513 been converted to Dart types (e.g. int, String), unless they are in | |
| 1514 the same package as the interface. | |
| 1515 super_interface: A string or None, the name of the common interface that | |
| 1516 this interface implements, if any. | |
| 1517 dart_code: an Emitter for the file containing the Dart implementation | |
| 1518 class. | |
| 1519 base_members: a set of names of members defined in a base class. This is | |
| 1520 used to avoid static member 'overriding' in the generated Dart code. | |
| 1521 """ | |
| 1522 self._interface = interface | |
| 1523 self._super_interface = super_interface | |
| 1524 self._dart_code = dart_code | |
| 1525 self._base_members = base_members | |
| 1526 self._current_secondary_parent = None | |
| 1527 | |
| 1528 | |
| 1529 def StartInterface(self): | |
| 1530 interface = self._interface | |
| 1531 interface_name = interface.id | |
| 1532 | |
| 1533 self._class_name = self._ImplClassName(interface_name) | |
| 1534 | |
| 1535 base = self._BaseClassName(interface) | |
| 1536 | |
| 1537 (self._members_emitter, | |
| 1538 self._top_level_emitter) = self._dart_code.Emit( | |
| 1539 '\n' | |
| 1540 'class $CLASS extends $BASE implements $INTERFACE {\n' | |
| 1541 ' $CLASS() : super() {}\n' | |
| 1542 '\n' | |
| 1543 ' static create_$CLASS() native {\n' | |
| 1544 ' return new $CLASS();\n' | |
| 1545 ' }\n' | |
| 1546 '$!MEMBERS' | |
| 1547 '\n' | |
| 1548 ' String get typeName() { return "$INTERFACE"; }\n' | |
| 1549 '}\n' | |
| 1550 '$!TOP_LEVEL', | |
| 1551 CLASS=self._class_name, BASE=base, INTERFACE=interface_name) | |
| 1552 | |
| 1553 def _ImplClassName(self, type_name): | |
| 1554 return '_' + type_name + 'WrappingImplementation' | |
| 1555 | |
| 1556 def _BaseClassName(self, interface): | |
| 1557 if not interface.parents: | |
| 1558 return 'DOMWrapperBase' | |
| 1559 | |
| 1560 supertype = interface.parents[0].type.id | |
| 1561 | |
| 1562 # FIXME: We're currently injecting List<..> and EventTarget as | |
| 1563 # supertypes in dart.idl. We should annotate/preserve as | |
| 1564 # attributes instead. For now, this hack lets the interfaces | |
| 1565 # inherit, but not the classes. | |
| 1566 # List methods are injected in AddIndexer. | |
| 1567 if _IsDartListType(supertype) or _IsDartCollectionType(supertype): | |
| 1568 return 'DOMWrapperBase' | |
| 1569 | |
| 1570 if supertype == 'EventTarget': | |
| 1571 # Most implementors of EventTarget specify the EventListener operations | |
| 1572 # again. If the operations are not specified, try to inherit from the | |
| 1573 # EventTarget implementation. | |
| 1574 # | |
| 1575 # Applies to MessagePort. | |
| 1576 if not [op for op in interface.operations if op.id == 'addEventListener']: | |
| 1577 return self._ImplClassName(supertype) | |
| 1578 return 'DOMWrapperBase' | |
| 1579 | |
| 1580 return self._ImplClassName(supertype) | |
| 1581 | |
| 1582 def FinishInterface(self): | |
| 1583 """.""" | |
| 1584 pass | |
| 1585 | |
| 1586 def AddConstant(self, constant): | |
| 1587 # Constants are already defined on the interface. | |
| 1588 pass | |
| 1589 | |
| 1590 def _MethodName(self, prefix, name): | |
| 1591 method_name = prefix + name | |
| 1592 if name in self._base_members: # Avoid illegal Dart 'static override'. | |
| 1593 method_name = method_name + '_' + self._interface.id | |
| 1594 return method_name | |
| 1595 | |
| 1596 def AddAttribute(self, getter, setter): | |
| 1597 if getter: | |
| 1598 self._AddGetter(getter) | |
| 1599 if setter: | |
| 1600 self._AddSetter(setter) | |
| 1601 | |
| 1602 def _AddGetter(self, attr): | |
| 1603 # FIXME: Instead of injecting the interface name into the method when it is | |
| 1604 # also implemented in the base class, suppress the method altogether if it | |
| 1605 # has the same signature. I.e., let the JS do the virtual dispatch instead. | |
| 1606 method_name = self._MethodName('_get_', attr.id) | |
| 1607 self._members_emitter.Emit( | |
| 1608 '\n' | |
| 1609 ' $TYPE get $NAME() { return $METHOD(this); }\n' | |
| 1610 ' static $TYPE $METHOD(var _this) native;\n', | |
| 1611 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name) | |
| 1612 | |
| 1613 def _AddSetter(self, attr): | |
| 1614 # FIXME: See comment on getter. | |
| 1615 method_name = self._MethodName('_set_', attr.id) | |
| 1616 self._members_emitter.Emit( | |
| 1617 '\n' | |
| 1618 ' void set $NAME($TYPE value) { $METHOD(this, value); }\n' | |
| 1619 ' static void $METHOD(var _this, $TYPE value) native;\n', | |
| 1620 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name) | |
| 1621 | |
| 1622 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 1623 self._SecondaryContext(interface) | |
| 1624 self.AddAttribute(getter, setter) | |
| 1625 | |
| 1626 def AddSecondaryOperation(self, interface, info): | |
| 1627 self._SecondaryContext(interface) | |
| 1628 self.AddOperation(info) | |
| 1629 | |
| 1630 def AddEventAttributes(self, event_attrs): | |
| 1631 pass | |
| 1632 | |
| 1633 def _SecondaryContext(self, interface): | |
| 1634 if interface is not self._current_secondary_parent: | |
| 1635 self._current_secondary_parent = interface | |
| 1636 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) | |
| 1637 | |
| 1638 def AddIndexer(self, element_type): | |
| 1639 """Adds all the methods required to complete implementation of List.""" | |
| 1640 # We would like to simply inherit the implementation of everything except | |
| 1641 # get length(), [], and maybe []=. It is possible to extend from a base | |
| 1642 # array implementation class only when there is no other implementation | |
| 1643 # inheritance. There might be no implementation inheritance other than | |
| 1644 # DOMBaseWrapper for many classes, but there might be some where the | |
| 1645 # array-ness is introduced by a non-root interface: | |
| 1646 # | |
| 1647 # interface Y extends X, List<T> ... | |
| 1648 # | |
| 1649 # In the non-root case we have to choose between: | |
| 1650 # | |
| 1651 # class YImpl extends XImpl { add List<T> methods; } | |
| 1652 # | |
| 1653 # and | |
| 1654 # | |
| 1655 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
| 1656 # | |
| 1657 if self._HasNativeIndexGetter(self._interface): | |
| 1658 self._EmitNativeIndexGetter(self._interface, element_type) | |
| 1659 else: | |
| 1660 self._members_emitter.Emit( | |
| 1661 '\n' | |
| 1662 ' $TYPE operator[](int index) {\n' | |
| 1663 ' return item(index);\n' | |
| 1664 ' }\n', | |
| 1665 TYPE=element_type) | |
| 1666 | |
| 1667 if self._HasNativeIndexSetter(self._interface): | |
| 1668 self._EmitNativeIndexSetter(self._interface, element_type) | |
| 1669 else: | |
| 1670 self._members_emitter.Emit( | |
| 1671 '\n' | |
| 1672 ' void operator[]=(int index, $TYPE value) {\n' | |
| 1673 ' throw new UnsupportedOperationException("Cannot assign element of
immutable List.");\n' | |
| 1674 ' }\n', | |
| 1675 TYPE=element_type) | |
| 1676 | |
| 1677 self._members_emitter.Emit( | |
| 1678 '\n' | |
| 1679 ' void add($TYPE value) {\n' | |
| 1680 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
| 1681 ' }\n' | |
| 1682 '\n' | |
| 1683 ' void addLast($TYPE value) {\n' | |
| 1684 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
| 1685 ' }\n' | |
| 1686 '\n' | |
| 1687 ' void addAll(Collection<$TYPE> collection) {\n' | |
| 1688 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
| 1689 ' }\n' | |
| 1690 '\n' | |
| 1691 ' void sort(int compare($TYPE a, $TYPE b)) {\n' | |
| 1692 ' throw new UnsupportedOperationException("Cannot sort immutable List
.");\n' | |
| 1693 ' }\n' | |
| 1694 '\n' | |
| 1695 ' void copyFrom(List<Object> src, int srcStart, ' | |
| 1696 'int dstStart, int count) {\n' | |
| 1697 ' throw new UnsupportedOperationException("This object is immutable."
);\n' | |
| 1698 ' }\n' | |
| 1699 '\n' | |
| 1700 ' int indexOf($TYPE element, [int start = 0]) {\n' | |
| 1701 ' return _Lists.indexOf(this, element, start, this.length);\n' | |
| 1702 ' }\n' | |
| 1703 '\n' | |
| 1704 ' int lastIndexOf($TYPE element, [int start = null]) {\n' | |
| 1705 ' if (start === null) start = length - 1;\n' | |
| 1706 ' return _Lists.lastIndexOf(this, element, start);\n' | |
| 1707 ' }\n' | |
| 1708 '\n' | |
| 1709 ' int clear() {\n' | |
| 1710 ' throw new UnsupportedOperationException("Cannot clear immutable Lis
t.");\n' | |
| 1711 ' }\n' | |
| 1712 '\n' | |
| 1713 ' $TYPE removeLast() {\n' | |
| 1714 ' throw new UnsupportedOperationException("Cannot removeLast on immut
able List.");\n' | |
| 1715 ' }\n' | |
| 1716 '\n' | |
| 1717 ' $TYPE last() {\n' | |
| 1718 ' return this[length - 1];\n' | |
| 1719 ' }\n' | |
| 1720 '\n' | |
| 1721 ' void forEach(void f($TYPE element)) {\n' | |
| 1722 ' _Collections.forEach(this, f);\n' | |
| 1723 ' }\n' | |
| 1724 '\n' | |
| 1725 ' Collection map(f($TYPE element)) {\n' | |
| 1726 ' return _Collections.map(this, [], f);\n' | |
| 1727 ' }\n' | |
| 1728 '\n' | |
| 1729 ' Collection<$TYPE> filter(bool f($TYPE element)) {\n' | |
| 1730 ' return _Collections.filter(this, new List<$TYPE>(), f);\n' | |
| 1731 ' }\n' | |
| 1732 '\n' | |
| 1733 ' bool every(bool f($TYPE element)) {\n' | |
| 1734 ' return _Collections.every(this, f);\n' | |
| 1735 ' }\n' | |
| 1736 '\n' | |
| 1737 ' bool some(bool f($TYPE element)) {\n' | |
| 1738 ' return _Collections.some(this, f);\n' | |
| 1739 ' }\n' | |
| 1740 '\n' | |
| 1741 ' void setRange(int start, int length, List<$TYPE> from, [int startFrom
]) {\n' | |
| 1742 ' throw new UnsupportedOperationException("Cannot setRange on immutab
le List.");\n' | |
| 1743 ' }\n' | |
| 1744 '\n' | |
| 1745 ' void removeRange(int start, int length) {\n' | |
| 1746 ' throw new UnsupportedOperationException("Cannot removeRange on immu
table List.");\n' | |
| 1747 ' }\n' | |
| 1748 '\n' | |
| 1749 ' void insertRange(int start, int length, [$TYPE initialValue]) {\n' | |
| 1750 ' throw new UnsupportedOperationException("Cannot insertRange on immu
table List.");\n' | |
| 1751 ' }\n' | |
| 1752 '\n' | |
| 1753 ' List<$TYPE> getRange(int start, int length) {\n' | |
| 1754 ' throw new NotImplementedException();\n' | |
| 1755 ' }\n' | |
| 1756 '\n' | |
| 1757 ' bool isEmpty() {\n' | |
| 1758 ' return length == 0;\n' | |
| 1759 ' }\n' | |
| 1760 '\n' | |
| 1761 ' Iterator<$TYPE> iterator() {\n' | |
| 1762 ' return new _FixedSizeListIterator<$TYPE>(this);\n' | |
| 1763 ' }\n', | |
| 1764 TYPE=element_type) | |
| 1765 | |
| 1766 def _HasNativeIndexGetter(self, interface): | |
| 1767 return ('HasIndexGetter' in interface.ext_attrs or | |
| 1768 'HasNumericIndexGetter' in interface.ext_attrs) | |
| 1769 | |
| 1770 def _EmitNativeIndexGetter(self, interface, element_type): | |
| 1771 method_name = '_index' | |
| 1772 self._members_emitter.Emit( | |
| 1773 '\n' | |
| 1774 ' $TYPE operator[](int index) { return $METHOD(this, index); }\n' | |
| 1775 ' static $TYPE $METHOD(var _this, int index) native;\n', | |
| 1776 TYPE=element_type, METHOD=method_name) | |
| 1777 | |
| 1778 def _HasNativeIndexSetter(self, interface): | |
| 1779 return 'HasCustomIndexSetter' in interface.ext_attrs | |
| 1780 | |
| 1781 def _EmitNativeIndexSetter(self, interface, element_type): | |
| 1782 method_name = '_set_index' | |
| 1783 self._members_emitter.Emit( | |
| 1784 '\n' | |
| 1785 ' void operator[]=(int index, $TYPE value) {\n' | |
| 1786 ' return $METHOD(this, index, value);\n' | |
| 1787 ' }\n' | |
| 1788 ' static $METHOD(_this, index, value) native;\n', | |
| 1789 TYPE=element_type, METHOD=method_name) | |
| 1790 | |
| 1791 def AddOperation(self, info): | |
| 1792 """ | |
| 1793 Arguments: | |
| 1794 info: An OperationInfo object. | |
| 1795 """ | |
| 1796 body = self._members_emitter.Emit( | |
| 1797 '\n' | |
| 1798 ' $TYPE $NAME($PARAMS) {\n' | |
| 1799 '$!BODY' | |
| 1800 ' }\n', | |
| 1801 TYPE=info.type_name, | |
| 1802 NAME=info.name, | |
| 1803 PARAMS=info.ParametersImplementationDeclaration()) | |
| 1804 | |
| 1805 # Process in order of ascending number of arguments to ensure missing | |
| 1806 # optional arguments are processed early. | |
| 1807 overloads = sorted(info.overloads, | |
| 1808 key=lambda overload: len(overload.arguments)) | |
| 1809 self._native_version = 0 | |
| 1810 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | |
| 1811 if fallthrough: | |
| 1812 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
| 1813 | |
| 1814 def GenerateSingleOperation(self, emitter, info, indent, operation): | |
| 1815 """Generates a call to a single operation. | |
| 1816 | |
| 1817 Arguments: | |
| 1818 emitter: an Emitter for the body of a block of code. | |
| 1819 info: the compound information about the operation and its overloads. | |
| 1820 indent: an indentation string for generated code. | |
| 1821 operation: the IDLOperation to call. | |
| 1822 """ | |
| 1823 # TODO(sra): Do we need to distinguish calling with missing optional | |
| 1824 # arguments from passing 'null' which is represented as 'undefined'? | |
| 1825 def UnwrapArgExpression(name, type): | |
| 1826 # TODO: Type specific unwrapping. | |
| 1827 return '__dom_unwrap(%s)' % (name) | |
| 1828 | |
| 1829 def ArgNameAndUnwrapper(arg_info, overload_arg): | |
| 1830 (name, type, value) = arg_info | |
| 1831 return (name, UnwrapArgExpression(name, type)) | |
| 1832 | |
| 1833 names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg) | |
| 1834 for (i, arg) in enumerate(operation.arguments)] | |
| 1835 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers] | |
| 1836 arg_names = [name for (name, _) in names_and_unwrappers] | |
| 1837 | |
| 1838 self._native_version += 1 | |
| 1839 native_name = self._MethodName('_', info.name) | |
| 1840 if self._native_version > 1: | |
| 1841 native_name = '%s_%s' % (native_name, self._native_version) | |
| 1842 | |
| 1843 argument_expressions = ', '.join(['this'] + arg_names) | |
| 1844 if info.type_name != 'void': | |
| 1845 emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n', | |
| 1846 INDENT=indent, | |
| 1847 NATIVENAME=native_name, | |
| 1848 ARGS=argument_expressions) | |
| 1849 else: | |
| 1850 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n' | |
| 1851 '$(INDENT)return;\n', | |
| 1852 INDENT=indent, | |
| 1853 NATIVENAME=native_name, | |
| 1854 ARGS=argument_expressions) | |
| 1855 | |
| 1856 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n', | |
| 1857 NAME=native_name, | |
| 1858 TYPE=info.type_name, | |
| 1859 PARAMS=', '.join(['receiver'] + arg_names) ) | |
| 1860 | |
| 1861 | |
| 1862 def GenerateDispatch(self, emitter, info, indent, position, overloads): | |
| 1863 """Generates a dispatch to one of the overloads. | |
| 1864 | |
| 1865 Arguments: | |
| 1866 emitter: an Emitter for the body of a block of code. | |
| 1867 info: the compound information about the operation and its overloads. | |
| 1868 indent: an indentation string for generated code. | |
| 1869 position: the index of the parameter to dispatch on. | |
| 1870 overloads: a list of the remaining IDLOperations to dispatch. | |
| 1871 | |
| 1872 Returns True if the dispatch can fall through on failure, False if the code | |
| 1873 always dispatches. | |
| 1874 """ | |
| 1875 | |
| 1876 def NullCheck(name): | |
| 1877 return '%s === null' % name | |
| 1878 | |
| 1879 def TypeCheck(name, type): | |
| 1880 return '%s is %s' % (name, type) | |
| 1881 | |
| 1882 if position == len(info.arg_infos): | |
| 1883 if len(overloads) > 1: | |
| 1884 raise Exception('Duplicate operations ' + str(overloads)) | |
| 1885 operation = overloads[0] | |
| 1886 self.GenerateSingleOperation(emitter, info, indent, operation) | |
| 1887 return False | |
| 1888 | |
| 1889 # FIXME: Consider a simpler dispatch that iterates over the | |
| 1890 # overloads and generates an overload specific check. Revisit | |
| 1891 # when we move to named optional arguments. | |
| 1892 | |
| 1893 # Partition the overloads to divide and conquer on the dispatch. | |
| 1894 positive = [] | |
| 1895 negative = [] | |
| 1896 first_overload = overloads[0] | |
| 1897 (param_name, param_type, param_default) = info.arg_infos[position] | |
| 1898 | |
| 1899 if position < len(first_overload.arguments): | |
| 1900 # FIXME: This will not work if the second overload has a more | |
| 1901 # precise type than the first. E.g., | |
| 1902 # void foo(Node x); | |
| 1903 # void foo(Element x); | |
| 1904 type = first_overload.arguments[position].type.id | |
| 1905 test = TypeCheck(param_name, type) | |
| 1906 pred = lambda op: len(op.arguments) > position and op.arguments[position].
type.id == type | |
| 1907 else: | |
| 1908 type = None | |
| 1909 test = NullCheck(param_name) | |
| 1910 pred = lambda op: position >= len(op.arguments) | |
| 1911 | |
| 1912 for overload in overloads: | |
| 1913 if pred(overload): | |
| 1914 positive.append(overload) | |
| 1915 else: | |
| 1916 negative.append(overload) | |
| 1917 | |
| 1918 if positive and negative: | |
| 1919 (true_code, false_code) = emitter.Emit( | |
| 1920 '$(INDENT)if ($COND) {\n' | |
| 1921 '$!TRUE' | |
| 1922 '$(INDENT)} else {\n' | |
| 1923 '$!FALSE' | |
| 1924 '$(INDENT)}\n', | |
| 1925 COND=test, INDENT=indent) | |
| 1926 fallthrough1 = self.GenerateDispatch( | |
| 1927 true_code, info, indent + ' ', position + 1, positive) | |
| 1928 fallthrough2 = self.GenerateDispatch( | |
| 1929 false_code, info, indent + ' ', position, negative) | |
| 1930 return fallthrough1 or fallthrough2 | |
| 1931 | |
| 1932 if negative: | |
| 1933 raise Exception('Internal error, must be all positive') | |
| 1934 | |
| 1935 # All overloads require the same test. Do we bother? | |
| 1936 | |
| 1937 # If the test is the same as the method's formal parameter then checked mode | |
| 1938 # will have done the test already. (It could be null too but we ignore that | |
| 1939 # case since all the overload behave the same and we don't know which types | |
| 1940 # in the IDL are not nullable.) | |
| 1941 if type == param_type: | |
| 1942 return self.GenerateDispatch( | |
| 1943 emitter, info, indent, position + 1, positive) | |
| 1944 | |
| 1945 # Otherwise the overloads have the same type but the type is a substype of | |
| 1946 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
| 1947 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
| 1948 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
| 1949 # that Y = Z-X, so we need to check for Y. | |
| 1950 true_code = emitter.Emit( | |
| 1951 '$(INDENT)if ($COND) {\n' | |
| 1952 '$!TRUE' | |
| 1953 '$(INDENT)}\n', | |
| 1954 COND=test, INDENT=indent) | |
| 1955 self.GenerateDispatch( | |
| 1956 true_code, info, indent + ' ', position + 1, positive) | |
| 1957 return True | |
| 1958 | |
| 1959 | |
| 1960 # ------------------------------------------------------------------------------ | |
| 1961 | |
| 1962 class FrogInterfaceGenerator(object): | |
| 1963 """Generates a Frog class for a DOM IDL interface.""" | |
| 1964 | |
| 1965 def __init__(self, system, interface, template, super_interface, dart_code): | |
| 1966 """Generates Dart code for the given interface. | |
| 1967 | |
| 1968 Args: | |
| 1969 | |
| 1970 interface: an IDLInterface instance. It is assumed that all types have | |
| 1971 been converted to Dart types (e.g. int, String), unless they are in | |
| 1972 the same package as the interface. | |
| 1973 template: A string template. | |
| 1974 super_interface: A string or None, the name of the common interface that | |
| 1975 this interface implements, if any. | |
| 1976 dart_code: an Emitter for the file containing the Dart implementation | |
| 1977 class. | |
| 1978 """ | |
| 1979 self._system = system | |
| 1980 self._interface = interface | |
| 1981 self._template = template | |
| 1982 self._super_interface = super_interface | |
| 1983 self._dart_code = dart_code | |
| 1984 self._current_secondary_parent = None | |
| 1985 | |
| 1986 | |
| 1987 def StartInterface(self): | |
| 1988 interface = self._interface | |
| 1989 interface_name = interface.id | |
| 1990 | |
| 1991 self._class_name = self._ImplClassName(interface_name) | |
| 1992 | |
| 1993 base = None | |
| 1994 if interface.parents: | |
| 1995 supertype = interface.parents[0].type.id | |
| 1996 if _IsDartCollectionType(supertype): | |
| 1997 # List methods are injected in AddIndexer. | |
| 1998 pass | |
| 1999 else: | |
| 2000 base = self._ImplClassName(supertype) | |
| 2001 | |
| 2002 if interface_name in _frog_dom_custom_native_specs: | |
| 2003 native_spec = _frog_dom_custom_native_specs[interface_name] | |
| 2004 else: | |
| 2005 # Make the class 'hidden' so it is dynamically patched at runtime. This | |
| 2006 # is useful not only for browser compat, but to allow code that links | |
| 2007 # against dart:dom to load in a worker isolate. | |
| 2008 native_spec = '*' + interface_name | |
| 2009 | |
| 2010 if base: | |
| 2011 extends = ' extends ' + base | |
| 2012 elif native_spec[0] == '=': | |
| 2013 # The implementation is a singleton with no prototype. | |
| 2014 extends = '' | |
| 2015 else: | |
| 2016 extends = ' extends _DOMTypeJs' | |
| 2017 | |
| 2018 # TODO: Include all implemented interfaces, including other Lists. | |
| 2019 implements = [interface_name] | |
| 2020 element_type = MaybeTypedArrayElementType(self._interface) | |
| 2021 if element_type: | |
| 2022 implements.append('List<' + element_type + '>') | |
| 2023 | |
| 2024 self._members_emitter = self._dart_code.Emit( | |
| 2025 self._template, | |
| 2026 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | |
| 2027 #$!MEMBERS | |
| 2028 #} | |
| 2029 CLASSNAME=self._class_name, | |
| 2030 EXTENDS=extends, | |
| 2031 IMPLEMENTS=' implements ' + ', '.join(implements), | |
| 2032 NATIVESPEC=' native "' + native_spec + '"') | |
| 2033 | |
| 2034 element_type = MaybeTypedArrayElementType(interface) | |
| 2035 if element_type: | |
| 2036 self.AddTypedArrayConstructors(element_type) | |
| 2037 | |
| 2038 | |
| 2039 def FinishInterface(self): | |
| 2040 """.""" | |
| 2041 pass | |
| 2042 | |
| 2043 def _ImplClassName(self, type_name): | |
| 2044 return '_' + type_name + 'Js' | |
| 2045 | |
| 2046 def _NarrowToImplementationType(self, type_name): | |
| 2047 # TODO(sra): Move into the 'system' and cache the result. | |
| 2048 if type_name == 'EventListener': | |
| 2049 # Callbacks are typedef functions so don't have a class. | |
| 2050 return type_name | |
| 2051 if self._system._database.HasInterface(type_name): | |
| 2052 interface = self._system._database.GetInterface(type_name) | |
| 2053 if _RecognizeCallback(interface): | |
| 2054 # Callbacks are typedef functions so don't have a class. | |
| 2055 return type_name | |
| 2056 else: | |
| 2057 return self._ImplClassName(type_name) | |
| 2058 return type_name | |
| 2059 | |
| 2060 def _NarrowInputType(self, type_name): | |
| 2061 return self._NarrowToImplementationType(type_name) | |
| 2062 | |
| 2063 def _NarrowOutputType(self, type_name): | |
| 2064 return self._NarrowToImplementationType(type_name) | |
| 2065 | |
| 2066 def AddConstant(self, constant): | |
| 2067 # Since we are currently generating native classes without interfaces, | |
| 2068 # generate the constants as part of the class. This will need to go away | |
| 2069 # if we revert back to generating interfaces. | |
| 2070 self._members_emitter.Emit('\n static final $TYPE $NAME = $VALUE;\n', | |
| 2071 NAME=constant.id, | |
| 2072 TYPE=constant.type.id, | |
| 2073 VALUE=constant.value) | |
| 2074 | |
| 2075 pass | |
| 2076 | |
| 2077 def AddAttribute(self, getter, setter): | |
| 2078 output_type = getter and self._NarrowOutputType(getter.type.id) | |
| 2079 input_type = setter and self._NarrowInputType(setter.type.id) | |
| 2080 | |
| 2081 # If the (getter, setter) pair is shadowing, we can't generate a shadowing | |
| 2082 # field (Issue 1633). | |
| 2083 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) | |
| 2084 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) | |
| 2085 if super_getter or super_setter: | |
| 2086 if getter and not setter and super_getter and not super_setter: | |
| 2087 if getter.type.id == super_getter.type.id: | |
| 2088 # Compatible getter, use the superclass property. This works because | |
| 2089 # JavaScript will do its own dynamic dispatch. | |
| 2090 self._members_emitter.Emit( | |
| 2091 '\n' | |
| 2092 ' // Use implementation from $SUPER.\n' | |
| 2093 ' // final $TYPE $NAME;\n', | |
| 2094 SUPER=super_getter_interface.id, | |
| 2095 NAME=getter.id, TYPE=output_type) | |
| 2096 return | |
| 2097 | |
| 2098 self._members_emitter.Emit('\n // Shadowing definition.') | |
| 2099 self._AddAttributeUsingProperties(getter, setter) | |
| 2100 return | |
| 2101 | |
| 2102 if getter and setter and input_type == output_type: | |
| 2103 self._members_emitter.Emit( | |
| 2104 '\n $TYPE $NAME;\n', | |
| 2105 NAME=getter.id, TYPE=output_type) | |
| 2106 return | |
| 2107 if getter and not setter: | |
| 2108 self._members_emitter.Emit( | |
| 2109 '\n final $TYPE $NAME;\n', | |
| 2110 NAME=getter.id, TYPE=output_type) | |
| 2111 return | |
| 2112 self._AddAttributeUsingProperties(getter, setter) | |
| 2113 | |
| 2114 def _AddAttributeUsingProperties(self, getter, setter): | |
| 2115 if getter: | |
| 2116 self._AddGetter(getter) | |
| 2117 if setter: | |
| 2118 self._AddSetter(setter) | |
| 2119 | |
| 2120 def _AddGetter(self, attr): | |
| 2121 # TODO(sra): Remove native body when Issue 829 fixed. | |
| 2122 self._members_emitter.Emit( | |
| 2123 '\n $TYPE get $NAME() native "return this.$NAME;";\n', | |
| 2124 NAME=attr.id, TYPE=self._NarrowOutputType(attr.type.id)) | |
| 2125 | |
| 2126 def _AddSetter(self, attr): | |
| 2127 # TODO(sra): Remove native body when Issue 829 fixed. | |
| 2128 self._members_emitter.Emit( | |
| 2129 ' void set $NAME($TYPE value) native "this.$NAME = value;";\n', | |
| 2130 NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id)) | |
| 2131 | |
| 2132 def _FindShadowedAttribute(self, attr): | |
| 2133 """Returns (attribute, superinterface) or (None, None).""" | |
| 2134 def FindInParent(interface): | |
| 2135 """Returns matching attribute in parent, or None.""" | |
| 2136 if interface.parents: | |
| 2137 parent = interface.parents[0] | |
| 2138 if _IsDartCollectionType(parent.type.id): | |
| 2139 return (None, None) | |
| 2140 if self._system._database.HasInterface(parent.type.id): | |
| 2141 parent_interface = self._system._database.GetInterface(parent.type.id) | |
| 2142 attr2 = _FindMatchingAttribute(parent_interface, attr) | |
| 2143 if attr2: | |
| 2144 return (attr2, parent_interface) | |
| 2145 return FindInParent(parent_interface) | |
| 2146 return (None, None) | |
| 2147 | |
| 2148 return FindInParent(self._interface) if attr else (None, None) | |
| 2149 | |
| 2150 | |
| 2151 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 2152 self._SecondaryContext(interface) | |
| 2153 self.AddAttribute(getter, setter) | |
| 2154 | |
| 2155 def AddSecondaryOperation(self, interface, info): | |
| 2156 self._SecondaryContext(interface) | |
| 2157 self.AddOperation(info) | |
| 2158 | |
| 2159 def AddEventAttributes(self, event_attrs): | |
| 2160 pass | |
| 2161 | |
| 2162 def _SecondaryContext(self, interface): | |
| 2163 if interface is not self._current_secondary_parent: | |
| 2164 self._current_secondary_parent = interface | |
| 2165 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) | |
| 2166 | |
| 2167 def AddIndexer(self, element_type): | |
| 2168 """Adds all the methods required to complete implementation of List.""" | |
| 2169 # We would like to simply inherit the implementation of everything except | |
| 2170 # get length(), [], and maybe []=. It is possible to extend from a base | |
| 2171 # array implementation class only when there is no other implementation | |
| 2172 # inheritance. There might be no implementation inheritance other than | |
| 2173 # DOMBaseWrapper for many classes, but there might be some where the | |
| 2174 # array-ness is introduced by a non-root interface: | |
| 2175 # | |
| 2176 # interface Y extends X, List<T> ... | |
| 2177 # | |
| 2178 # In the non-root case we have to choose between: | |
| 2179 # | |
| 2180 # class YImpl extends XImpl { add List<T> methods; } | |
| 2181 # | |
| 2182 # and | |
| 2183 # | |
| 2184 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
| 2185 # | |
| 2186 self._members_emitter.Emit( | |
| 2187 '\n' | |
| 2188 ' $TYPE operator[](int index) native "return this[index];";\n', | |
| 2189 TYPE=self._NarrowOutputType(element_type)) | |
| 2190 | |
| 2191 if 'HasCustomIndexSetter' in self._interface.ext_attrs: | |
| 2192 self._members_emitter.Emit( | |
| 2193 '\n' | |
| 2194 ' void operator[]=(int index, $TYPE value) native "this[index] = valu
e";\n', | |
| 2195 TYPE=self._NarrowInputType(element_type)) | |
| 2196 else: | |
| 2197 self._members_emitter.Emit( | |
| 2198 '\n' | |
| 2199 ' void operator[]=(int index, $TYPE value) {\n' | |
| 2200 ' throw new UnsupportedOperationException("Cannot assign element of
immutable List.");\n' | |
| 2201 ' }\n', | |
| 2202 TYPE=self._NarrowInputType(element_type)) | |
| 2203 | |
| 2204 # TODO(sra): Use separate mixins for mutable implementations of List<T>. | |
| 2205 # TODO(sra): Use separate mixins for typed array implementations of List<T>. | |
| 2206 template_file = 'immutable_list_mixin.darttemplate' | |
| 2207 template = self._system._templates.Load(template_file) | |
| 2208 self._members_emitter.Emit(template, E=element_type) | |
| 2209 | |
| 2210 | |
| 2211 def AddTypedArrayConstructors(self, element_type): | |
| 2212 self._members_emitter.Emit( | |
| 2213 '\n' | |
| 2214 ' factory $CTOR(int length) => _construct_$CTOR(length);\n' | |
| 2215 '\n' | |
| 2216 ' factory $CTOR.fromList(List<$TYPE> list) => _construct_$CTOR(list);\n
' | |
| 2217 '\n' | |
| 2218 ' factory $CTOR.fromBuffer(ArrayBuffer buffer) => _construct_$CTOR(buff
er);\n' | |
| 2219 '\n' | |
| 2220 ' static _construct_$CTOR(arg) native \'return new $CTOR(arg);\';\n', | |
| 2221 CTOR=self._interface.id, | |
| 2222 TYPE=element_type) | |
| 2223 | |
| 2224 | |
| 2225 def AddOperation(self, info): | |
| 2226 """ | |
| 2227 Arguments: | |
| 2228 info: An OperationInfo object. | |
| 2229 """ | |
| 2230 # TODO(vsm): Handle overloads. | |
| 2231 self._members_emitter.Emit( | |
| 2232 '\n' | |
| 2233 ' $TYPE $NAME($PARAMS) native;\n', | |
| 2234 TYPE=self._NarrowOutputType(info.type_name), | |
| 2235 NAME=info.name, | |
| 2236 PARAMS=info.ParametersImplementationDeclaration( | |
| 2237 lambda type_name: self._NarrowInputType(type_name))) | |
| 2238 | |
| 2239 | |
| 2240 # ------------------------------------------------------------------------------ | |
| 2241 | |
| 2242 # TODO(jmesserly): inheritance is probably not the right way to factor this long | |
| 2243 # term, but it makes merging better for now. | |
| 2244 class HtmlFrogInterfaceGenerator(FrogInterfaceGenerator): | |
| 2245 """Generates a Frog class for the dart:html library from a DOM IDL | |
| 2246 interface. | |
| 2247 """ | |
| 2248 | |
| 2249 def __init__(self, system, interface, template, super_interface, dart_code): | |
| 2250 super(HtmlFrogInterfaceGenerator, self).__init__( | |
| 2251 system, interface, template, super_interface, dart_code) | |
| 2252 | |
| 2253 def AddEventAttributes(self, event_attrs): | |
| 2254 events_class = self._interface.id + 'EventsImpl' | |
| 2255 events_interface = self._interface.id + 'Events' | |
| 2256 self._members_emitter.Emit('\n $TYPE get on() =>\n new $TYPE(this);\n', | |
| 2257 TYPE=events_class) | |
| 2258 | |
| 2259 events_members = self._dart_code.Emit( | |
| 2260 '\n' | |
| 2261 'class $CLASSNAME extends EventsImplementation ' | |
| 2262 'implements $INTERFACE {\n' | |
| 2263 ' $CLASSNAME(_ptr) : super._wrap(_ptr);\n' | |
| 2264 '$!MEMBERS}\n', | |
| 2265 CLASSNAME=events_class, | |
| 2266 INTERFACE=events_interface) | |
| 2267 | |
| 2268 for getter, setter in event_attrs: | |
| 2269 event = getter or setter | |
| 2270 events_members.Emit( | |
| 2271 "\n" | |
| 2272 "EventListenerList get $NAME() => _get('$NAME');\n", | |
| 2273 NAME=event.id) | |
| 2274 | |
| 2275 | |
| 2276 # ------------------------------------------------------------------------------ | |
| 2277 | |
| 2278 class NativeImplementationSystem(System): | 695 class NativeImplementationSystem(System): |
| 2279 | 696 |
| 2280 def __init__(self, templates, database, emitters, auxiliary_dir, output_dir): | 697 def __init__(self, templates, database, emitters, auxiliary_dir, output_dir): |
| 2281 super(NativeImplementationSystem, self).__init__( | 698 super(NativeImplementationSystem, self).__init__( |
| 2282 templates, database, emitters, output_dir) | 699 templates, database, emitters, output_dir) |
| 2283 | 700 |
| 2284 self._auxiliary_dir = auxiliary_dir | 701 self._auxiliary_dir = auxiliary_dir |
| 2285 self._dom_public_files = [] | 702 self._dom_public_files = [] |
| 2286 self._dom_impl_files = [] | 703 self._dom_impl_files = [] |
| 2287 self._cpp_header_files = [] | 704 self._cpp_header_files = [] |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2538 INDENT=indent, | 955 INDENT=indent, |
| 2539 NATIVENAME=native_name, | 956 NATIVENAME=native_name, |
| 2540 ARGS=argument_expressions) | 957 ARGS=argument_expressions) |
| 2541 | 958 |
| 2542 self._members_emitter.Emit(' $TYPE $NATIVE_NAME($PARAMS) native ' | 959 self._members_emitter.Emit(' $TYPE $NATIVE_NAME($PARAMS) native ' |
| 2543 '"$(INTERFACE)$(NATIVE_NAME)_Callback";\n', | 960 '"$(INTERFACE)$(NATIVE_NAME)_Callback";\n', |
| 2544 NATIVE_NAME=native_name, | 961 NATIVE_NAME=native_name, |
| 2545 TYPE=info.type_name, | 962 TYPE=info.type_name, |
| 2546 PARAMS=', '.join(arg_names), | 963 PARAMS=', '.join(arg_names), |
| 2547 INTERFACE=self._interface.id) | 964 INTERFACE=self._interface.id) |
| OLD | NEW |