| 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 generator import * |
| 16 from systembase import * |
| 17 from systemfrog import * |
| 18 from systemhtml import * |
| 19 from systeminterface import * |
| 15 | 20 |
| 16 _logger = logging.getLogger('dartgenerator') | 21 _logger = logging.getLogger('dartgenerator') |
| 17 | 22 |
| 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): | 23 class DartGenerator(object): |
| 143 """Utilities to generate Dart APIs and corresponding JavaScript.""" | 24 """Utilities to generate Dart APIs and corresponding JavaScript.""" |
| 144 | 25 |
| 145 def __init__(self, auxiliary_dir, template_dir, base_package): | 26 def __init__(self, auxiliary_dir, template_dir, base_package): |
| 146 """Constructor for the DartGenerator. | 27 """Constructor for the DartGenerator. |
| 147 | 28 |
| 148 Args: | 29 Args: |
| 149 auxiliary_dir -- location of auxiliary handwritten classes | 30 auxiliary_dir -- location of auxiliary handwritten classes |
| 150 template_dir -- location of template files | 31 template_dir -- location of template files |
| 151 base_package -- the base package name for the generated code. | 32 base_package -- the base package name for the generated code. |
| 152 """ | 33 """ |
| 153 self._auxiliary_dir = auxiliary_dir | 34 self._auxiliary_dir = auxiliary_dir |
| 154 self._template_dir = template_dir | 35 self._template_dir = template_dir |
| 155 self._base_package = base_package | 36 self._base_package = base_package |
| 156 self._auxiliary_files = {} | 37 self._auxiliary_files = {} |
| 157 self._dart_templates_re = re.compile(r'[\w.:]+<([\w\.<>:]+)>') | 38 self._dart_templates_re = re.compile(r'[\w.:]+<([\w\.<>:]+)>') |
| 158 | 39 |
| 159 self._emitters = None # set later | 40 self._emitters = None # set later |
| 160 | 41 |
| 161 | 42 |
| 162 def _StripModules(self, type_name): | 43 def _StripModules(self, type_name): |
| 163 return type_name.split('::')[-1] | 44 return type_name.split('::')[-1] |
| 164 | 45 |
| 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): | 46 def _IsCompoundType(self, database, type_name): |
| 170 if self._IsPrimitiveType(type_name): | 47 if IsPrimitiveType(type_name): |
| 171 return True | 48 return True |
| 172 | 49 |
| 173 striped_type_name = self._StripModules(type_name) | 50 striped_type_name = self._StripModules(type_name) |
| 174 if database.HasInterface(striped_type_name): | 51 if database.HasInterface(striped_type_name): |
| 175 return True | 52 return True |
| 176 | 53 |
| 177 dart_template_match = self._dart_templates_re.match(type_name) | 54 dart_template_match = self._dart_templates_re.match(type_name) |
| 178 if dart_template_match: | 55 if dart_template_match: |
| 179 # Dart templates | 56 # Dart templates |
| 180 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] | 57 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] |
| 181 sub_type_name = dart_template_match.group(1) | 58 sub_type_name = dart_template_match.group(1) |
| 182 return (self._IsCompoundType(database, parent_type_name) and | 59 return (self._IsCompoundType(database, parent_type_name) and |
| 183 self._IsCompoundType(database, sub_type_name)) | 60 self._IsCompoundType(database, sub_type_name)) |
| 184 return False | 61 return False |
| 185 | 62 |
| 186 def _IsDartType(self, type_name): | 63 def _IsDartType(self, type_name): |
| 187 return '.' in type_name | 64 return '.' in type_name |
| 188 | 65 |
| 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): | 66 def LoadAuxiliary(self): |
| 199 def Visitor(_, dirname, names): | 67 def Visitor(_, dirname, names): |
| 200 for name in names: | 68 for name in names: |
| 201 if name.endswith('.dart'): | 69 if name.endswith('.dart'): |
| 202 name = name[0:-5] # strip off ".dart" | 70 name = name[0:-5] # strip off ".dart" |
| 203 self._auxiliary_files[name] = os.path.join(dirname, name) | 71 self._auxiliary_files[name] = os.path.join(dirname, name) |
| 204 os.path.walk(self._auxiliary_dir, Visitor, None) | 72 os.path.walk(self._auxiliary_dir, Visitor, None) |
| 205 | 73 |
| 206 def RenameTypes(self, database, conversion_table=None): | 74 def RenameTypes(self, database, conversion_table, rename_javascript_binding_na
mes): |
| 207 """Renames interfaces using the given conversion table. | 75 """Renames interfaces using the given conversion table. |
| 208 | 76 |
| 209 References through all interfaces will be renamed as well. | 77 References through all interfaces will be renamed as well. |
| 210 | 78 |
| 211 Args: | 79 Args: |
| 212 database: the database to apply the renames to. | 80 database: the database to apply the renames to. |
| 213 conversion_table: maps old names to new names. | 81 conversion_table: maps old names to new names. |
| 214 """ | 82 """ |
| 215 | 83 |
| 216 if conversion_table is None: | 84 if conversion_table is None: |
| 217 conversion_table = {} | 85 conversion_table = {} |
| 218 | 86 |
| 219 # Rename interfaces: | 87 # Rename interfaces: |
| 220 for old_name, new_name in conversion_table.items(): | 88 for old_name, new_name in conversion_table.items(): |
| 221 if database.HasInterface(old_name): | 89 if database.HasInterface(old_name): |
| 222 _logger.info('renaming interface %s to %s' % | 90 _logger.info('renaming interface %s to %s' % (old_name, new_name)) |
| 223 (old_name, new_name)) | |
| 224 interface = database.GetInterface(old_name) | 91 interface = database.GetInterface(old_name) |
| 225 database.DeleteInterface(old_name) | 92 database.DeleteInterface(old_name) |
| 226 if not database.HasInterface(new_name): | 93 if not database.HasInterface(new_name): |
| 227 interface.id = new_name | 94 interface.id = new_name |
| 228 database.AddInterface(interface) | 95 database.AddInterface(interface) |
| 229 | 96 else: |
| 97 new_interface = database.GetInterface(new_name) |
| 98 new_interface.merge(interface) |
| 99 |
| 100 interface.javascript_binding_name = (old_name if rename_javascript_bindi
ng_names |
| 101 else new_name) |
| 102 |
| 230 # Fix references: | 103 # Fix references: |
| 231 for interface in database.GetInterfaces(): | 104 for interface in database.GetInterfaces(): |
| 232 for idl_type in interface.all(idlnode.IDLType): | 105 for idl_type in interface.all(idlnode.IDLType): |
| 233 type_name = self._StripModules(idl_type.id) | 106 type_name = self._StripModules(idl_type.id) |
| 234 if type_name in conversion_table: | 107 if type_name in conversion_table: |
| 235 idl_type.id = conversion_table[type_name] | 108 idl_type.id = conversion_table[type_name] |
| 236 | 109 |
| 237 def FilterMembersWithUnidentifiedTypes(self, database): | 110 def FilterMembersWithUnidentifiedTypes(self, database): |
| 238 """Removes unidentified types. | 111 """Removes unidentified types. |
| 239 | 112 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 258 interface.attributes = filter(IsIdentified, interface.attributes) | 131 interface.attributes = filter(IsIdentified, interface.attributes) |
| 259 interface.operations = filter(IsIdentified, interface.operations) | 132 interface.operations = filter(IsIdentified, interface.operations) |
| 260 interface.parents = filter(IsIdentified, interface.parents) | 133 interface.parents = filter(IsIdentified, interface.parents) |
| 261 | 134 |
| 262 def ConvertToDartTypes(self, database): | 135 def ConvertToDartTypes(self, database): |
| 263 """Converts all IDL types to Dart primitives or qualified types""" | 136 """Converts all IDL types to Dart primitives or qualified types""" |
| 264 | 137 |
| 265 def ConvertType(interface, type_name): | 138 def ConvertType(interface, type_name): |
| 266 """Helper method for converting a type name to the proper | 139 """Helper method for converting a type name to the proper |
| 267 Dart name""" | 140 Dart name""" |
| 268 if self._IsPrimitiveType(type_name): | 141 if IsPrimitiveType(type_name): |
| 269 return self._ConvertPrimitiveType(type_name) | 142 return ConvertPrimitiveType(type_name) |
| 270 | 143 |
| 271 if self._IsDartType(type_name): | 144 if self._IsDartType(type_name): |
| 272 # This is for when dart qualified names are explicitly | 145 # This is for when dart qualified names are explicitly |
| 273 # defined in the IDLs. Just let them be. | 146 # defined in the IDLs. Just let them be. |
| 274 return type_name | 147 return type_name |
| 275 | 148 |
| 276 dart_template_match = self._dart_templates_re.match(type_name) | 149 dart_template_match = self._dart_templates_re.match(type_name) |
| 277 if dart_template_match: | 150 if dart_template_match: |
| 278 # Dart templates | 151 # Dart templates |
| 279 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] | 152 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 interface.parents = filter(HasAnnotations, interface.parents) | 221 interface.parents = filter(HasAnnotations, interface.parents) |
| 349 else: | 222 else: |
| 350 database.DeleteInterface(interface.id) | 223 database.DeleteInterface(interface.id) |
| 351 | 224 |
| 352 self.FilterMembersWithUnidentifiedTypes(database) | 225 self.FilterMembersWithUnidentifiedTypes(database) |
| 353 | 226 |
| 354 | 227 |
| 355 def Generate(self, database, output_dir, | 228 def Generate(self, database, output_dir, |
| 356 module_source_preference=[], source_filter=None, | 229 module_source_preference=[], source_filter=None, |
| 357 super_database=None, common_prefix=None, super_map={}, | 230 super_database=None, common_prefix=None, super_map={}, |
| 358 lib_dir=None, systems=[]): | 231 html_map={}, lib_dir=None, systems=[]): |
| 359 """Generates Dart and JS files for the loaded interfaces. | 232 """Generates Dart and JS files for the loaded interfaces. |
| 360 | 233 |
| 361 Args: | 234 Args: |
| 362 database -- database containing interfaces to generate code for. | 235 database -- database containing interfaces to generate code for. |
| 363 output_dir -- directory to write generated files to. | 236 output_dir -- directory to write generated files to. |
| 364 module_source_preference -- priority order list of source annotations to | 237 module_source_preference -- priority order list of source annotations to |
| 365 use when choosing a module name, if none specified uses the module name | 238 use when choosing a module name, if none specified uses the module name |
| 366 from the database. | 239 from the database. |
| 367 source_filter -- if specified, only outputs interfaces that have one of | 240 source_filter -- if specified, only outputs interfaces that have one of |
| 368 these source annotation and rewrites the names of superclasses not | 241 these source annotation and rewrites the names of superclasses not |
| 369 marked with this source to use the common prefix. | 242 marked with this source to use the common prefix. |
| 370 super_database -- database containing super interfaces that the generated | 243 super_database -- database containing super interfaces that the generated |
| 371 interfaces should extend. | 244 interfaces should extend. |
| 372 common_prefix -- prefix for the common library, if any. | 245 common_prefix -- prefix for the common library, if any. |
| 373 lib_file_path -- filename for generated .lib file, None if not required. | 246 lib_file_path -- filename for generated .lib file, None if not required. |
| 374 lib_template -- template file in this directory for generated lib file. | 247 lib_template -- template file in this directory for generated lib file. |
| 375 """ | 248 """ |
| 376 | 249 |
| 377 self._emitters = multiemitter.MultiEmitter() | 250 self._emitters = multiemitter.MultiEmitter() |
| 378 self._database = database | 251 self._database = database |
| 379 self._output_dir = output_dir | 252 self._output_dir = output_dir |
| 380 | 253 |
| 381 self._ComputeInheritanceClosure() | 254 self._ComputeInheritanceClosure() |
| 382 | 255 |
| 383 self._systems = [] | 256 self._systems = [] |
| 384 | 257 |
| 385 # TODO(jmesserly): only create these if needed | 258 # TODO(jmesserly): only create these if needed |
| 386 interface_system = InterfacesSystem( | 259 if ('htmlfrog' in systems) or ('htmldartium' in systems): |
| 387 TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), | 260 html_interface_system = HtmlInterfacesSystem( |
| 388 self._database, self._emitters, self._output_dir) | 261 TemplateLoader(self._template_dir, ['html/interface', 'html', '']), |
| 389 self._systems.append(interface_system) | 262 self._database, self._emitters, self._output_dir, self) |
| 390 | 263 self._systems.append(html_interface_system) |
| 391 html_interface_system = HtmlInterfacesSystem( | 264 else: |
| 392 TemplateLoader(self._template_dir, ['html/interface', 'html', '']), | 265 interface_system = InterfacesSystem( |
| 393 self._database, self._emitters, self._output_dir) | 266 TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), |
| 394 self._systems.append(html_interface_system) | 267 self._database, self._emitters, self._output_dir) |
| 268 self._systems.append(interface_system) |
| 395 | 269 |
| 396 if 'native' in systems: | 270 if 'native' in systems: |
| 397 native_system = NativeImplementationSystem( | 271 native_system = NativeImplementationSystem( |
| 398 TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), | 272 TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), |
| 399 self._database, self._emitters, self._auxiliary_dir, | 273 self._database, self._emitters, self._auxiliary_dir, |
| 400 self._output_dir) | 274 self._output_dir) |
| 401 | 275 |
| 402 self._systems.append(native_system) | 276 self._systems.append(native_system) |
| 403 | 277 |
| 404 if 'wrapping' in systems: | 278 if 'wrapping' in systems: |
| (...skipping 20 matching lines...) Expand all Loading... |
| 425 frog_system = FrogSystem( | 299 frog_system = FrogSystem( |
| 426 TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), | 300 TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), |
| 427 self._database, self._emitters, self._output_dir) | 301 self._database, self._emitters, self._output_dir) |
| 428 | 302 |
| 429 frog_system._interface_system = interface_system | 303 frog_system._interface_system = interface_system |
| 430 self._systems.append(frog_system) | 304 self._systems.append(frog_system) |
| 431 | 305 |
| 432 if 'htmlfrog' in systems: | 306 if 'htmlfrog' in systems: |
| 433 html_system = HtmlFrogSystem( | 307 html_system = HtmlFrogSystem( |
| 434 TemplateLoader(self._template_dir, ['html/frog', 'html', '']), | 308 TemplateLoader(self._template_dir, ['html/frog', 'html', '']), |
| 435 self._database, self._emitters, self._output_dir) | 309 self._database, self._emitters, self._output_dir, self) |
| 436 | 310 |
| 437 html_system._interface_system = html_interface_system | 311 html_system._interface_system = html_interface_system |
| 438 self._systems.append(html_system) | 312 self._systems.append(html_system) |
| 439 | 313 |
| 440 if 'htmldartium' in systems: | 314 if 'htmldartium' in systems: |
| 441 html_system = HtmlDartiumSystem( | 315 html_system = HtmlDartiumSystem( |
| 442 TemplateLoader(self._template_dir, ['html/dartium', 'html', '']), | 316 TemplateLoader(self._template_dir, ['html/dartium', 'html', '']), |
| 443 self._database, self._emitters, self._output_dir) | 317 self._database, self._emitters, self._output_dir, self) |
| 444 | 318 |
| 445 html_system._interface_system = html_interface_system | 319 html_system._interface_system = html_interface_system |
| 446 self._systems.append(html_system) | 320 self._systems.append(html_system) |
| 447 | 321 |
| 448 # Collect interfaces | 322 # Collect interfaces |
| 449 interfaces = [] | 323 interfaces = [] |
| 450 for interface in database.GetInterfaces(): | 324 for interface in database.GetInterfaces(): |
| 451 if not _MatchSourceFilter(source_filter, interface): | 325 if not MatchSourceFilter(source_filter, interface): |
| 452 # Skip this interface since it's not present in the required source | 326 # Skip this interface since it's not present in the required source |
| 453 _logger.info('Omitting interface - %s' % interface.id) | 327 _logger.info('Omitting interface - %s' % interface.id) |
| 454 continue | 328 continue |
| 455 interfaces.append(interface) | 329 interfaces.append(interface) |
| 456 | 330 |
| 457 # TODO(sra): Use this list of exception names to generate information to | 331 # TODO(sra): Use this list of exception names to generate information to |
| 458 # tell Frog which exceptions can be passed from JS to Dart code. | 332 # tell Frog which exceptions can be passed from JS to Dart code. |
| 459 exceptions = self._CollectExceptions(interfaces) | 333 exceptions = self._CollectExceptions(interfaces) |
| 460 | 334 |
| 461 # Render all interfaces into Dart and save them in files. | 335 # Render all interfaces into Dart and save them in files. |
| 462 for interface in self._PreOrderInterfaces(interfaces): | 336 for interface in self._PreOrderInterfaces(interfaces): |
| 463 | 337 |
| 464 super_interface = None | 338 super_interface = None |
| 465 super_name = interface.id | 339 super_name = interface.id |
| 466 | 340 |
| 467 if super_name in super_map: | 341 if super_name in super_map: |
| 468 super_name = super_map[super_name] | 342 super_name = super_map[super_name] |
| 469 | 343 |
| 470 if (super_database is not None and | 344 if (super_database is not None and |
| 471 super_database.HasInterface(super_name)): | 345 super_database.HasInterface(super_name)): |
| 472 super_interface = super_name | 346 super_interface = super_name |
| 473 | 347 |
| 474 interface_name = interface.id | 348 interface_name = interface.id |
| 475 auxiliary_file = self._auxiliary_files.get(interface_name) | 349 auxiliary_file = self._auxiliary_files.get(interface_name) |
| 476 if auxiliary_file is not None: | 350 if auxiliary_file is not None: |
| 477 _logger.info('Skipping %s because %s exists' % ( | 351 _logger.info('Skipping %s because %s exists' % ( |
| 478 interface_name, auxiliary_file)) | 352 interface_name, auxiliary_file)) |
| 479 continue | 353 continue |
| 480 | 354 |
| 481 info = _RecognizeCallback(interface) | 355 info = RecognizeCallback(interface) |
| 482 if info: | 356 if info: |
| 483 for system in self._systems: | 357 for system in self._systems: |
| 484 system.ProcessCallback(interface, info) | 358 system.ProcessCallback(interface, info) |
| 485 else: | 359 else: |
| 486 if 'Callback' in interface.ext_attrs: | 360 if 'Callback' in interface.ext_attrs: |
| 487 _logger.info('Malformed callback: %s' % interface.id) | 361 _logger.info('Malformed callback: %s' % interface.id) |
| 488 self._ProcessInterface(interface, super_interface, | 362 self._ProcessInterface(interface, super_interface, |
| 489 source_filter, common_prefix) | 363 source_filter, common_prefix) |
| 490 | 364 |
| 491 # Libraries | 365 # Libraries |
| 492 if lib_dir: | 366 if lib_dir: |
| 493 for system in self._systems: | 367 for system in self._systems: |
| 494 system.GenerateLibraries(lib_dir) | 368 system.GenerateLibraries(lib_dir) |
| 495 | 369 |
| 496 for system in self._systems: | 370 for system in self._systems: |
| 497 system.Finish() | 371 system.Finish() |
| 498 | 372 |
| 499 | 373 |
| 500 def _PreOrderInterfaces(self, interfaces): | 374 def _PreOrderInterfaces(self, interfaces): |
| 501 """Returns the interfaces in pre-order, i.e. parents first.""" | 375 """Returns the interfaces in pre-order, i.e. parents first.""" |
| 502 seen = set() | 376 seen = set() |
| 503 ordered = [] | 377 ordered = [] |
| 504 def visit(interface): | 378 def visit(interface): |
| 505 if interface.id in seen: | 379 if interface.id in seen: |
| 506 return | 380 return |
| 507 seen.add(interface.id) | 381 seen.add(interface.id) |
| 508 for parent in interface.parents: | 382 for parent in interface.parents: |
| 509 if _IsDartCollectionType(parent.type.id): | 383 if IsDartCollectionType(parent.type.id): |
| 510 continue | 384 continue |
| 511 if self._database.HasInterface(parent.type.id): | 385 if self._database.HasInterface(parent.type.id): |
| 512 parent_interface = self._database.GetInterface(parent.type.id) | 386 parent_interface = self._database.GetInterface(parent.type.id) |
| 513 visit(parent_interface) | 387 visit(parent_interface) |
| 514 ordered.append(interface) | 388 ordered.append(interface) |
| 515 | 389 |
| 516 for interface in interfaces: | 390 for interface in interfaces: |
| 517 visit(interface) | 391 visit(interface) |
| 518 return ordered | 392 return ordered |
| 519 | 393 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 537 for const in sorted(interface.constants, ConstantOutputOrder): | 411 for const in sorted(interface.constants, ConstantOutputOrder): |
| 538 for generator in generators: | 412 for generator in generators: |
| 539 generator.AddConstant(const) | 413 generator.AddConstant(const) |
| 540 | 414 |
| 541 attributes = [attr for attr in interface.attributes | 415 attributes = [attr for attr in interface.attributes |
| 542 if not self._IsEventAttribute(interface, attr)] | 416 if not self._IsEventAttribute(interface, attr)] |
| 543 for (getter, setter) in _PairUpAttributes(attributes): | 417 for (getter, setter) in _PairUpAttributes(attributes): |
| 544 for generator in generators: | 418 for generator in generators: |
| 545 generator.AddAttribute(getter, setter) | 419 generator.AddAttribute(getter, setter) |
| 546 | 420 |
| 547 events = _PairUpAttributes([attr for attr in interface.attributes | 421 events = set([attr for attr in interface.attributes |
| 548 if self._IsEventAttribute(interface, attr)]) | 422 if self._IsEventAttribute(interface, attr)]) |
| 423 |
| 549 if events: | 424 if events: |
| 550 for generator in generators: | 425 for generator in generators: |
| 551 generator.AddEventAttributes(events) | 426 generator.AddEventAttributes(events) |
| 552 | 427 |
| 553 # The implementation should define an indexer if the interface directly | 428 # The implementation should define an indexer if the interface directly |
| 554 # extends List. | 429 # extends List. |
| 555 element_type = MaybeListElementType(interface) | 430 element_type = MaybeListElementType(interface) |
| 556 if element_type: | 431 if element_type: |
| 557 for generator in generators: | 432 for generator in generators: |
| 558 generator.AddIndexer(element_type) | 433 generator.AddIndexer(element_type) |
| 559 | |
| 560 # Group overloaded operations by id | 434 # Group overloaded operations by id |
| 561 operationsById = {} | 435 operationsById = {} |
| 562 for operation in interface.operations: | 436 for operation in interface.operations: |
| 563 if operation.id not in operationsById: | 437 if operation.id not in operationsById: |
| 564 operationsById[operation.id] = [] | 438 operationsById[operation.id] = [] |
| 565 operationsById[operation.id].append(operation) | 439 operationsById[operation.id].append(operation) |
| 566 | 440 |
| 567 # Generate operations | 441 # Generate operations |
| 568 for id in sorted(operationsById.keys()): | 442 for id in sorted(operationsById.keys()): |
| 569 operations = operationsById[id] | 443 operations = operationsById[id] |
| 570 info = _AnalyzeOperation(interface, operations) | 444 info = AnalyzeOperation(interface, operations) |
| 571 for generator in generators: | 445 for generator in generators: |
| 572 generator.AddOperation(info) | 446 generator.AddOperation(info) |
| 573 | 447 |
| 574 # With multiple inheritance, attributes and operations of non-first | 448 # With multiple inheritance, attributes and operations of non-first |
| 575 # interfaces need to be added. Sometimes the attribute or operation is | 449 # interfaces need to be added. Sometimes the attribute or operation is |
| 576 # defined in the current interface as well as a parent. In that case we | 450 # defined in the current interface as well as a parent. In that case we |
| 577 # avoid making a duplicate definition and pray that the signatures match. | 451 # avoid making a duplicate definition and pray that the signatures match. |
| 578 | 452 |
| 579 for parent_interface in self._TransitiveSecondaryParents(interface): | 453 for parent_interface in self._TransitiveSecondaryParents(interface): |
| 580 if isinstance(parent_interface, str): # _IsDartCollectionType(parent_inte
rface) | 454 if isinstance(parent_interface, str): # IsDartCollectionType(parent_inter
face) |
| 581 continue | 455 continue |
| 582 attributes = [attr for attr in parent_interface.attributes | 456 attributes = [attr for attr in parent_interface.attributes |
| 583 if not _FindMatchingAttribute(interface, attr)] | 457 if not FindMatchingAttribute(interface, attr)] |
| 584 for (getter, setter) in _PairUpAttributes(attributes): | 458 for (getter, setter) in _PairUpAttributes(attributes): |
| 585 for generator in generators: | 459 for generator in generators: |
| 586 generator.AddSecondaryAttribute(parent_interface, getter, setter) | 460 generator.AddSecondaryAttribute(parent_interface, getter, setter) |
| 587 | 461 |
| 588 # Group overloaded operations by id | 462 # Group overloaded operations by id |
| 589 operationsById = {} | 463 operationsById = {} |
| 590 for operation in parent_interface.operations: | 464 for operation in parent_interface.operations: |
| 591 if operation.id not in operationsById: | 465 if operation.id not in operationsById: |
| 592 operationsById[operation.id] = [] | 466 operationsById[operation.id] = [] |
| 593 operationsById[operation.id].append(operation) | 467 operationsById[operation.id].append(operation) |
| 594 | 468 |
| 595 # Generate operations | 469 # Generate operations |
| 596 for id in sorted(operationsById.keys()): | 470 for id in sorted(operationsById.keys()): |
| 597 if not any(op.id == id for op in interface.operations): | 471 if not any(op.id == id for op in interface.operations): |
| 598 operations = operationsById[id] | 472 operations = operationsById[id] |
| 599 info = _AnalyzeOperation(interface, operations) | 473 info = AnalyzeOperation(interface, operations) |
| 600 for generator in generators: | 474 for generator in generators: |
| 601 generator.AddSecondaryOperation(parent_interface, info) | 475 generator.AddSecondaryOperation(parent_interface, info) |
| 602 | 476 |
| 603 for generator in generators: | 477 for generator in generators: |
| 604 generator.FinishInterface() | 478 generator.FinishInterface() |
| 605 return | 479 return |
| 606 | 480 |
| 607 def _IsEventAttribute(self, interface, attr): | 481 def _IsEventAttribute(self, interface, attr): |
| 608 # Remove EventListener attributes like 'onclick' when addEventListener | 482 # Remove EventListener attributes like 'onclick' when addEventListener |
| 609 # is available. | 483 # is available. |
| 610 if attr.type.id == 'EventListener': | 484 return (attr.type.id == 'EventListener' and |
| 611 if 'EventTarget' in self._AllImplementedInterfaces(interface): | 485 'EventTarget' in self._AllImplementedInterfaces(interface)) |
| 612 return True | |
| 613 return False | |
| 614 | 486 |
| 615 def _TransitiveSecondaryParents(self, interface): | 487 def _TransitiveSecondaryParents(self, interface): |
| 616 """Returns a list of all non-primary parents. | 488 """Returns a list of all non-primary parents. |
| 617 | 489 |
| 618 The list contains the interface objects for interfaces defined in the | 490 The list contains the interface objects for interfaces defined in the |
| 619 database, and the name for undefined interfaces. | 491 database, and the name for undefined interfaces. |
| 620 """ | 492 """ |
| 621 def walk(parents): | 493 def walk(parents): |
| 622 for parent in parents: | 494 for parent in parents: |
| 623 if _IsDartCollectionType(parent.type.id): | 495 if IsDartCollectionType(parent.type.id): |
| 624 result.append(parent.type.id) | 496 result.append(parent.type.id) |
| 625 continue | 497 continue |
| 626 if self._database.HasInterface(parent.type.id): | 498 if self._database.HasInterface(parent.type.id): |
| 627 parent_interface = self._database.GetInterface(parent.type.id) | 499 parent_interface = self._database.GetInterface(parent.type.id) |
| 628 result.append(parent_interface) | 500 result.append(parent_interface) |
| 629 walk(parent_interface.parents) | 501 walk(parent_interface.parents) |
| 630 | 502 |
| 631 result = [] | 503 result = [] |
| 632 walk(interface.parents[1:]) | 504 walk(interface.parents[1:]) |
| 633 return result; | 505 return result; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 collected = [] | 548 collected = [] |
| 677 Collect(interface, seen, collected) | 549 Collect(interface, seen, collected) |
| 678 self._inheritance_closure[interface.id] = collected | 550 self._inheritance_closure[interface.id] = collected |
| 679 | 551 |
| 680 def _AllImplementedInterfaces(self, interface): | 552 def _AllImplementedInterfaces(self, interface): |
| 681 """Returns a list of the names of all interfaces implemented by 'interface'. | 553 """Returns a list of the names of all interfaces implemented by 'interface'. |
| 682 List includes the name of 'interface'. | 554 List includes the name of 'interface'. |
| 683 """ | 555 """ |
| 684 return self._inheritance_closure[interface.id] | 556 return self._inheritance_closure[interface.id] |
| 685 | 557 |
| 686 | |
| 687 def _RecognizeCallback(interface): | |
| 688 """Returns the info for the callback method if the interface smells like a | |
| 689 callback. | |
| 690 """ | |
| 691 if 'Callback' not in interface.ext_attrs: return None | |
| 692 handlers = [op for op in interface.operations if op.id == 'handleEvent'] | |
| 693 if not handlers: return None | |
| 694 if not (handlers == interface.operations): return None | |
| 695 return _AnalyzeOperation(interface, handlers) | |
| 696 | |
| 697 | |
| 698 def _PairUpAttributes(attributes): | 558 def _PairUpAttributes(attributes): |
| 699 """Returns a list of (getter, setter) pairs sorted by name. | 559 """Returns a list of (getter, setter) pairs sorted by name. |
| 700 | 560 |
| 701 One element of the pair may be None. | 561 One element of the pair may be None. |
| 702 """ | 562 """ |
| 703 names = sorted(set(attr.id for attr in attributes)) | 563 names = sorted(set(attr.id for attr in attributes)) |
| 704 getters = {} | 564 getters = {} |
| 705 setters = {} | 565 setters = {} |
| 706 for attr in attributes: | 566 for attr in attributes: |
| 707 if attr.is_fc_getter: | 567 if attr.is_fc_getter: |
| 708 getters[attr.id] = attr | 568 getters[attr.id] = attr |
| 709 elif attr.is_fc_setter and 'Replaceable' not in attr.ext_attrs: | 569 elif attr.is_fc_setter and 'Replaceable' not in attr.ext_attrs: |
| 710 setters[attr.id] = attr | 570 setters[attr.id] = attr |
| 711 return [(getters.get(id), setters.get(id)) for id in names] | 571 return [(getters.get(id), setters.get(id)) for id in names] |
| 712 | 572 |
| 713 | |
| 714 def _FindMatchingAttribute(interface, attr1): | |
| 715 matches = [attr2 for attr2 in interface.attributes | |
| 716 if attr1.id == attr2.id | |
| 717 and attr1.is_fc_getter == attr2.is_fc_getter | |
| 718 and attr1.is_fc_setter == attr2.is_fc_setter] | |
| 719 if matches: | |
| 720 assert len(matches) == 1 | |
| 721 return matches[0] | |
| 722 return None | |
| 723 | |
| 724 | |
| 725 def _AnalyzeOperation(interface, operations): | |
| 726 """Makes operation calling convention decision for a set of overloads. | |
| 727 | |
| 728 Returns: An OperationInfo object. | |
| 729 """ | |
| 730 | |
| 731 # Zip together arguments from each overload by position, then convert | |
| 732 # to a dart argument. | |
| 733 | |
| 734 # Given a list of overloaded arguments, choose a suitable name. | |
| 735 def OverloadedName(args): | |
| 736 return '_OR_'.join(sorted(set(arg.id for arg in args))) | |
| 737 | |
| 738 # Given a list of overloaded arguments, choose a suitable type. | |
| 739 def OverloadedType(args): | |
| 740 typeIds = sorted(set(arg.type.id for arg in args)) | |
| 741 if len(typeIds) == 1: | |
| 742 return typeIds[0] | |
| 743 else: | |
| 744 return TypeName(typeIds, interface) | |
| 745 | |
| 746 # Given a list of overloaded arguments, render a dart argument. | |
| 747 def DartArg(args): | |
| 748 filtered = filter(None, args) | |
| 749 optional = any(not arg or arg.is_optional for arg in args) | |
| 750 type = OverloadedType(filtered) | |
| 751 name = OverloadedName(filtered) | |
| 752 if optional: | |
| 753 return (name, type, 'null') | |
| 754 else: | |
| 755 return (name, type, None) | |
| 756 | |
| 757 args = map(lambda *args: DartArg(args), | |
| 758 *(op.arguments for op in operations)) | |
| 759 | |
| 760 info = OperationInfo() | |
| 761 info.overloads = operations | |
| 762 info.declared_name = operations[0].id | |
| 763 info.name = operations[0].ext_attrs.get('DartName', info.declared_name) | |
| 764 info.js_name = info.declared_name | |
| 765 info.type_name = operations[0].type.id # TODO: widen. | |
| 766 info.arg_infos = args | |
| 767 return info | |
| 768 | |
| 769 | |
| 770 class OperationInfo(object): | |
| 771 """Holder for various derived information from a set of overloaded operations. | |
| 772 | |
| 773 Attributes: | |
| 774 overloads: A list of IDL operation overloads with the same name. | |
| 775 name: A string, the simple name of the operation. | |
| 776 type_name: A string, the name of the return type of the operation. | |
| 777 arg_infos: A list of (name, type, default_value) tuples. | |
| 778 default_value is None for mandatory arguments. | |
| 779 """ | |
| 780 | |
| 781 def ParametersInterfaceDeclaration(self): | |
| 782 """Returns a formatted string declaring the parameters for the interface.""" | |
| 783 return self._FormatArgs(self.arg_infos, True) | |
| 784 | |
| 785 def ParametersImplementationDeclaration(self, rename_type=None): | |
| 786 """Returns a formatted string declaring the parameters for the | |
| 787 implementation. | |
| 788 | |
| 789 Args: | |
| 790 rename_type: A function that allows the types to be renamed. | |
| 791 """ | |
| 792 args = self.arg_infos | |
| 793 if rename_type: | |
| 794 args = [(name, rename_type(type), default) | |
| 795 for (name, type, default) in args] | |
| 796 return self._FormatArgs(args, False) | |
| 797 | |
| 798 | |
| 799 def _FormatArgs(self, args, is_interface): | |
| 800 def FormatArg(arg_info): | |
| 801 """Returns an argument declaration fragment for an argument info tuple.""" | |
| 802 (name, type, default) = arg_info | |
| 803 if default: | |
| 804 return '%s %s = %s' % (type, name, default) | |
| 805 else: | |
| 806 return '%s %s' % (type, name) | |
| 807 | |
| 808 required = [] | |
| 809 optional = [] | |
| 810 for (name, type, default) in args: | |
| 811 if default: | |
| 812 if is_interface: | |
| 813 optional.append((name, type, None)) # Default values illegal. | |
| 814 else: | |
| 815 optional.append((name, type, default)) | |
| 816 else: | |
| 817 if optional: | |
| 818 raise Exception('Optional arguments cannot precede required ones: ' | |
| 819 + str(args)) | |
| 820 required.append((name, type, None)) | |
| 821 argtexts = map(FormatArg, required) | |
| 822 if optional: | |
| 823 argtexts.append('[' + ', '.join(map(FormatArg, optional)) + ']') | |
| 824 return ', '.join(argtexts) | |
| 825 | |
| 826 | |
| 827 def MaybeListElementTypeName(type_name): | |
| 828 """Returns the List element type T from string of form "List<T>", or None.""" | |
| 829 match = re.match(r'List<(\w*)>$', type_name) | |
| 830 if match: | |
| 831 return match.group(1) | |
| 832 return None | |
| 833 | |
| 834 def MaybeListElementType(interface): | |
| 835 """Returns the List element type T, or None in interface does not implement | |
| 836 List<T>. | |
| 837 """ | |
| 838 for parent in interface.parents: | |
| 839 element_type = MaybeListElementTypeName(parent.type.id) | |
| 840 if element_type: | |
| 841 return element_type | |
| 842 return None | |
| 843 | |
| 844 def MaybeTypedArrayElementType(interface): | |
| 845 """Returns the typed array element type, or None in interface is not a | |
| 846 TypedArray. | |
| 847 """ | |
| 848 # Typed arrays implement ArrayBufferView and List<T>. | |
| 849 for parent in interface.parents: | |
| 850 if parent.type.id == 'ArrayBufferView': | |
| 851 return MaybeListElementType(interface) | |
| 852 if parent.type.id == 'Uint8Array': | |
| 853 return 'int' | |
| 854 return None | |
| 855 | |
| 856 | |
| 857 def AttributeOutputOrder(a, b): | |
| 858 """Canonical output ordering for attributes.""" | |
| 859 # Getters before setters: | |
| 860 if a.id < b.id: return -1 | |
| 861 if a.id > b.id: return 1 | |
| 862 if a.is_fc_setter < b.is_fc_setter: return -1 | |
| 863 if a.is_fc_setter > b.is_fc_setter: return 1 | |
| 864 return 0 | |
| 865 | |
| 866 def ConstantOutputOrder(a, b): | |
| 867 """Canonical output ordering for constants.""" | |
| 868 if a.id < b.id: return -1 | |
| 869 if a.id > b.id: return 1 | |
| 870 return 0 | |
| 871 | |
| 872 | |
| 873 def _FormatNameList(names): | |
| 874 """Returns JavaScript array literal expression with one name per line.""" | |
| 875 #names = sorted(names) | |
| 876 if len(names) <= 1: | |
| 877 expression_string = str(names) # e.g. ['length'] | |
| 878 else: | |
| 879 expression_string = ',\n '.join(str(names).split(',')) | |
| 880 expression_string = expression_string.replace('[', '[\n ') | |
| 881 return expression_string | |
| 882 | |
| 883 | |
| 884 def IndentText(text, indent): | |
| 885 """Format lines of text with indent.""" | |
| 886 def FormatLine(line): | |
| 887 if line.strip(): | |
| 888 return '%s%s\n' % (indent, line) | |
| 889 else: | |
| 890 return '\n' | |
| 891 return ''.join(FormatLine(line) for line in text.split('\n')) | |
| 892 | |
| 893 # ------------------------------------------------------------------------------ | 573 # ------------------------------------------------------------------------------ |
| 894 | 574 |
| 895 class TemplateLoader(object): | 575 class TemplateLoader(object): |
| 896 """Loads template files from a path.""" | 576 """Loads template files from a path.""" |
| 897 | 577 |
| 898 def __init__(self, root, subpaths): | 578 def __init__(self, root, subpaths): |
| 899 """Initializes loader. | 579 """Initializes loader. |
| 900 | 580 |
| 901 Args: | 581 Args: |
| 902 root - a string, the directory under which the templates are stored. | 582 root - a string, the directory under which the templates are stored. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 921 return None | 601 return None |
| 922 | 602 |
| 923 def Load(self, name): | 603 def Load(self, name): |
| 924 """Returns contents of template file as a string, or raises an exception.""" | 604 """Returns contents of template file as a string, or raises an exception.""" |
| 925 template = self.TryLoad(name) | 605 template = self.TryLoad(name) |
| 926 if template is not None: # Can be empty string | 606 if template is not None: # Can be empty string |
| 927 return template | 607 return template |
| 928 raise Exception("Could not find template '%s' on %s / %s" % ( | 608 raise Exception("Could not find template '%s' on %s / %s" % ( |
| 929 name, self._root, self._subpaths)) | 609 name, self._root, self._subpaths)) |
| 930 | 610 |
| 931 | |
| 932 # ------------------------------------------------------------------------------ | |
| 933 | |
| 934 class System(object): | |
| 935 """Generates all the files for one implementation.""" | |
| 936 | |
| 937 def __init__(self, templates, database, emitters, output_dir): | |
| 938 self._templates = templates | |
| 939 self._database = database | |
| 940 self._emitters = emitters | |
| 941 self._output_dir = output_dir | |
| 942 self._dart_callback_file_paths = [] | |
| 943 | |
| 944 def InterfaceGenerator(self, | |
| 945 interface, | |
| 946 common_prefix, | |
| 947 super_interface_name, | |
| 948 source_filter): | |
| 949 """Returns an interface generator for |interface|.""" | |
| 950 return None | |
| 951 | |
| 952 def ProcessCallback(self, interface, info): | |
| 953 pass | |
| 954 | |
| 955 def GenerateLibraries(self, lib_dir): | |
| 956 pass | |
| 957 | |
| 958 def Finish(self): | |
| 959 pass | |
| 960 | |
| 961 | |
| 962 def _ProcessCallback(self, interface, info, file_path): | |
| 963 """Generates a typedef for the callback interface.""" | |
| 964 self._dart_callback_file_paths.append(file_path) | |
| 965 code = self._emitters.FileEmitter(file_path) | |
| 966 | |
| 967 code.Emit(self._templates.Load('callback.darttemplate')) | |
| 968 code.Emit('typedef $TYPE $NAME($PARAMS);\n', | |
| 969 NAME=interface.id, | |
| 970 TYPE=info.type_name, | |
| 971 PARAMS=info.ParametersImplementationDeclaration()) | |
| 972 | |
| 973 def _GenerateLibFile(self, lib_template, lib_file_path, file_paths, | |
| 974 **template_args): | |
| 975 """Generates a lib file from a template and a list of files. | |
| 976 | |
| 977 Additional keyword arguments are passed to the template. | |
| 978 """ | |
| 979 # Load template. | |
| 980 template = self._templates.Load(lib_template) | |
| 981 # Generate the .lib file. | |
| 982 lib_file_contents = self._emitters.FileEmitter(lib_file_path) | |
| 983 | |
| 984 # Emit the list of #source directives. | |
| 985 list_emitter = lib_file_contents.Emit(template, **template_args) | |
| 986 lib_file_dir = os.path.dirname(lib_file_path) | |
| 987 for path in sorted(file_paths): | |
| 988 relpath = os.path.relpath(path, lib_file_dir) | |
| 989 list_emitter.Emit("#source('$PATH');\n", PATH=relpath) | |
| 990 | |
| 991 | |
| 992 def _BaseDefines(self, interface): | |
| 993 """Returns a set of names (strings) for members defined in a base class. | |
| 994 """ | |
| 995 def WalkParentChain(interface): | |
| 996 if interface.parents: | |
| 997 # Only consider primary parent, secondary parents are not on the | |
| 998 # implementation class inheritance chain. | |
| 999 parent = interface.parents[0] | |
| 1000 if _IsDartCollectionType(parent.type.id): | |
| 1001 return | |
| 1002 if self._database.HasInterface(parent.type.id): | |
| 1003 parent_interface = self._database.GetInterface(parent.type.id) | |
| 1004 for attr in parent_interface.attributes: | |
| 1005 result.add(attr.id) | |
| 1006 for op in parent_interface.operations: | |
| 1007 result.add(op.id) | |
| 1008 WalkParentChain(parent_interface) | |
| 1009 | |
| 1010 result = set() | |
| 1011 WalkParentChain(interface) | |
| 1012 return result; | |
| 1013 | |
| 1014 | |
| 1015 # ------------------------------------------------------------------------------ | |
| 1016 | |
| 1017 class InterfacesSystem(System): | |
| 1018 | |
| 1019 def __init__(self, templates, database, emitters, output_dir): | |
| 1020 super(InterfacesSystem, self).__init__( | |
| 1021 templates, database, emitters, output_dir) | |
| 1022 self._dart_interface_file_paths = [] | |
| 1023 | |
| 1024 | |
| 1025 def InterfaceGenerator(self, | |
| 1026 interface, | |
| 1027 common_prefix, | |
| 1028 super_interface_name, | |
| 1029 source_filter): | |
| 1030 """.""" | |
| 1031 interface_name = interface.id | |
| 1032 dart_interface_file_path = self._FilePathForDartInterface(interface_name) | |
| 1033 | |
| 1034 self._dart_interface_file_paths.append(dart_interface_file_path) | |
| 1035 | |
| 1036 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) | |
| 1037 | |
| 1038 template_file = 'interface_%s.darttemplate' % interface_name | |
| 1039 template = self._templates.TryLoad(template_file) | |
| 1040 if not template: | |
| 1041 template = self._templates.Load('interface.darttemplate') | |
| 1042 | |
| 1043 return DartInterfaceGenerator( | |
| 1044 interface, dart_interface_code, | |
| 1045 template, | |
| 1046 common_prefix, super_interface_name, | |
| 1047 source_filter) | |
| 1048 | |
| 1049 def ProcessCallback(self, interface, info): | |
| 1050 """Generates a typedef for the callback interface.""" | |
| 1051 interface_name = interface.id | |
| 1052 file_path = self._FilePathForDartInterface(interface_name) | |
| 1053 self._ProcessCallback(interface, info, file_path) | |
| 1054 | |
| 1055 def GenerateLibraries(self, lib_dir): | |
| 1056 pass | |
| 1057 | |
| 1058 | |
| 1059 def _FilePathForDartInterface(self, interface_name): | |
| 1060 """Returns the file path of the Dart interface definition.""" | |
| 1061 return os.path.join(self._output_dir, 'src', 'interface', | |
| 1062 '%s.dart' % interface_name) | |
| 1063 | |
| 1064 | |
| 1065 # ------------------------------------------------------------------------------ | |
| 1066 | |
| 1067 class HtmlInterfacesSystem(System): | |
| 1068 | |
| 1069 def __init__(self, templates, database, emitters, output_dir): | |
| 1070 super(HtmlInterfacesSystem, self).__init__( | |
| 1071 templates, database, emitters, output_dir) | |
| 1072 self._dart_interface_file_paths = [] | |
| 1073 | |
| 1074 def InterfaceGenerator(self, | |
| 1075 interface, | |
| 1076 common_prefix, | |
| 1077 super_interface_name, | |
| 1078 source_filter): | |
| 1079 """.""" | |
| 1080 interface_name = interface.id | |
| 1081 dart_interface_file_path = self._FilePathForDartInterface(interface_name) | |
| 1082 | |
| 1083 self._dart_interface_file_paths.append(dart_interface_file_path) | |
| 1084 | |
| 1085 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) | |
| 1086 | |
| 1087 template_file = 'interface_%s.darttemplate' % interface_name | |
| 1088 template = self._templates.TryLoad(template_file) | |
| 1089 if not template: | |
| 1090 template = self._templates.Load('interface.darttemplate') | |
| 1091 | |
| 1092 return HtmlDartInterfaceGenerator( | |
| 1093 interface, dart_interface_code, | |
| 1094 template, | |
| 1095 common_prefix, super_interface_name, | |
| 1096 source_filter) | |
| 1097 | |
| 1098 def ProcessCallback(self, interface, info): | |
| 1099 """Generates a typedef for the callback interface.""" | |
| 1100 interface_name = interface.id | |
| 1101 file_path = self._FilePathForDartInterface(interface_name) | |
| 1102 self._ProcessCallback(interface, info, file_path) | |
| 1103 | |
| 1104 def GenerateLibraries(self, lib_dir): | |
| 1105 pass | |
| 1106 | |
| 1107 | |
| 1108 def _FilePathForDartInterface(self, interface_name): | |
| 1109 """Returns the file path of the Dart interface definition.""" | |
| 1110 # TODO(jmesserly): is this the right path | |
| 1111 return os.path.join(self._output_dir, 'html', 'interface', | |
| 1112 '%s.dart' % interface_name) | |
| 1113 | |
| 1114 | |
| 1115 # ------------------------------------------------------------------------------ | 611 # ------------------------------------------------------------------------------ |
| 1116 | 612 |
| 1117 class DummyImplementationSystem(System): | 613 class DummyImplementationSystem(System): |
| 1118 """Generates a dummy implementation for use by the editor analysis. | 614 """Generates a dummy implementation for use by the editor analysis. |
| 1119 | 615 |
| 1120 All the code comes from hand-written library files. | 616 All the code comes from hand-written library files. |
| 1121 """ | 617 """ |
| 1122 | 618 |
| 1123 def __init__(self, templates, database, emitters, output_dir): | 619 def __init__(self, templates, database, emitters, output_dir): |
| 1124 super(DummyImplementationSystem, self).__init__( | 620 super(DummyImplementationSystem, self).__init__( |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1197 pass | 693 pass |
| 1198 | 694 |
| 1199 | 695 |
| 1200 def _FilePathForDartWrappingImpl(self, interface_name): | 696 def _FilePathForDartWrappingImpl(self, interface_name): |
| 1201 """Returns the file path of the Dart wrapping implementation.""" | 697 """Returns the file path of the Dart wrapping implementation.""" |
| 1202 return os.path.join(self._output_dir, 'src', 'wrapping', | 698 return os.path.join(self._output_dir, 'src', 'wrapping', |
| 1203 '_%sWrappingImplementation.dart' % interface_name) | 699 '_%sWrappingImplementation.dart' % interface_name) |
| 1204 | 700 |
| 1205 # ------------------------------------------------------------------------------ | 701 # ------------------------------------------------------------------------------ |
| 1206 | 702 |
| 1207 class FrogSystem(System): | |
| 1208 | |
| 1209 def __init__(self, templates, database, emitters, output_dir): | |
| 1210 super(FrogSystem, self).__init__( | |
| 1211 templates, database, emitters, output_dir) | |
| 1212 self._dart_frog_file_paths = [] | |
| 1213 | |
| 1214 def InterfaceGenerator(self, | |
| 1215 interface, | |
| 1216 common_prefix, | |
| 1217 super_interface_name, | |
| 1218 source_filter): | |
| 1219 """.""" | |
| 1220 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) | |
| 1221 self._dart_frog_file_paths.append(dart_frog_file_path) | |
| 1222 | |
| 1223 template_file = 'impl_%s.darttemplate' % interface.id | |
| 1224 template = self._templates.TryLoad(template_file) | |
| 1225 if not template: | |
| 1226 template = self._templates.Load('frog_impl.darttemplate') | |
| 1227 | |
| 1228 dart_code = self._emitters.FileEmitter(dart_frog_file_path) | |
| 1229 return FrogInterfaceGenerator(self, interface, template, | |
| 1230 super_interface_name, dart_code) | |
| 1231 | |
| 1232 def GenerateLibraries(self, lib_dir): | |
| 1233 self._GenerateLibFile( | |
| 1234 'frog_dom.darttemplate', | |
| 1235 os.path.join(lib_dir, 'dom_frog.dart'), | |
| 1236 (self._interface_system._dart_interface_file_paths + | |
| 1237 self._interface_system._dart_callback_file_paths + | |
| 1238 self._dart_frog_file_paths)) | |
| 1239 | |
| 1240 def Finish(self): | |
| 1241 pass | |
| 1242 | |
| 1243 def _FilePathForFrogImpl(self, interface_name): | |
| 1244 """Returns the file path of the Frog implementation.""" | |
| 1245 return os.path.join(self._output_dir, 'src', 'frog', | |
| 1246 '%s.dart' % interface_name) | |
| 1247 | |
| 1248 | |
| 1249 # ------------------------------------------------------------------------------ | |
| 1250 | |
| 1251 class HtmlFrogSystem(System): | |
| 1252 | |
| 1253 def __init__(self, templates, database, emitters, output_dir): | |
| 1254 super(HtmlFrogSystem, self).__init__( | |
| 1255 templates, database, emitters, output_dir) | |
| 1256 self._dart_frog_file_paths = [] | |
| 1257 | |
| 1258 def InterfaceGenerator(self, | |
| 1259 interface, | |
| 1260 common_prefix, | |
| 1261 super_interface_name, | |
| 1262 source_filter): | |
| 1263 """.""" | |
| 1264 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) | |
| 1265 self._dart_frog_file_paths.append(dart_frog_file_path) | |
| 1266 | |
| 1267 template_file = 'impl_%s.darttemplate' % interface.id | |
| 1268 template = self._templates.TryLoad(template_file) | |
| 1269 if not template: | |
| 1270 template = self._templates.Load('frog_impl.darttemplate') | |
| 1271 | |
| 1272 dart_code = self._emitters.FileEmitter(dart_frog_file_path) | |
| 1273 return HtmlFrogInterfaceGenerator(self, interface, template, | |
| 1274 super_interface_name, dart_code) | |
| 1275 | |
| 1276 def GenerateLibraries(self, lib_dir): | |
| 1277 self._GenerateLibFile( | |
| 1278 'html_frog.darttemplate', | |
| 1279 os.path.join(lib_dir, 'html_frog.dart'), | |
| 1280 (self._interface_system._dart_interface_file_paths + | |
| 1281 self._interface_system._dart_callback_file_paths + | |
| 1282 self._dart_frog_file_paths)) | |
| 1283 | |
| 1284 def Finish(self): | |
| 1285 pass | |
| 1286 | |
| 1287 def _FilePathForFrogImpl(self, interface_name): | |
| 1288 """Returns the file path of the Frog implementation.""" | |
| 1289 # TODO(jmesserly): is this the right path | |
| 1290 return os.path.join(self._output_dir, 'html', 'frog', | |
| 1291 '%s.dart' % interface_name) | |
| 1292 | |
| 1293 # ------------------------------------------------------------------------------ | |
| 1294 | |
| 1295 class DartInterfaceGenerator(object): | |
| 1296 """Generates Dart Interface definition for one DOM IDL interface.""" | |
| 1297 | |
| 1298 def __init__(self, interface, emitter, template, | |
| 1299 common_prefix, super_interface, source_filter): | |
| 1300 """Generates Dart code for the given interface. | |
| 1301 | |
| 1302 Args: | |
| 1303 interface -- an IDLInterface instance. It is assumed that all types have | |
| 1304 been converted to Dart types (e.g. int, String), unless they are in the | |
| 1305 same package as the interface. | |
| 1306 common_prefix -- the prefix for the common library, if any. | |
| 1307 super_interface -- the name of the common interface that this interface | |
| 1308 implements, if any. | |
| 1309 source_filter -- if specified, rewrites the names of any superinterfaces | |
| 1310 that are not from these sources to use the common prefix. | |
| 1311 """ | |
| 1312 self._interface = interface | |
| 1313 self._emitter = emitter | |
| 1314 self._template = template | |
| 1315 self._common_prefix = common_prefix | |
| 1316 self._super_interface = super_interface | |
| 1317 self._source_filter = source_filter | |
| 1318 | |
| 1319 | |
| 1320 def StartInterface(self): | |
| 1321 if self._super_interface: | |
| 1322 typename = self._super_interface | |
| 1323 else: | |
| 1324 typename = self._interface.id | |
| 1325 | |
| 1326 # TODO(vsm): Add appropriate package / namespace syntax. | |
| 1327 (extends_emitter, | |
| 1328 self._members_emitter, | |
| 1329 self._top_level_emitter) = self._emitter.Emit( | |
| 1330 self._template + '$!TOP_LEVEL', | |
| 1331 ID=typename) | |
| 1332 | |
| 1333 extends = [] | |
| 1334 suppressed_extends = [] | |
| 1335 | |
| 1336 for parent in self._interface.parents: | |
| 1337 # TODO(vsm): Remove source_filter. | |
| 1338 if _MatchSourceFilter(self._source_filter, parent): | |
| 1339 # Parent is a DOM type. | |
| 1340 extends.append(parent.type.id) | |
| 1341 elif '<' in parent.type.id: | |
| 1342 # Parent is a Dart collection type. | |
| 1343 # TODO(vsm): Make this check more robust. | |
| 1344 extends.append(parent.type.id) | |
| 1345 else: | |
| 1346 suppressed_extends.append('%s.%s' % | |
| 1347 (self._common_prefix, parent.type.id)) | |
| 1348 | |
| 1349 comment = ' extends' | |
| 1350 if extends: | |
| 1351 extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) | |
| 1352 comment = ',' | |
| 1353 if suppressed_extends: | |
| 1354 extends_emitter.Emit(' /*$COMMENT $SUPERS */', | |
| 1355 COMMENT=comment, | |
| 1356 SUPERS=', '.join(suppressed_extends)) | |
| 1357 | |
| 1358 if typename in _interface_factories: | |
| 1359 extends_emitter.Emit(' default $F', F=_interface_factories[typename]) | |
| 1360 | |
| 1361 element_type = MaybeTypedArrayElementType(self._interface) | |
| 1362 if element_type: | |
| 1363 self._members_emitter.Emit( | |
| 1364 '\n' | |
| 1365 ' $CTOR(int length);\n' | |
| 1366 '\n' | |
| 1367 ' $CTOR.fromList(List<$TYPE> list);\n' | |
| 1368 '\n' | |
| 1369 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n', | |
| 1370 CTOR=self._interface.id, | |
| 1371 TYPE=element_type) | |
| 1372 | |
| 1373 | |
| 1374 def FinishInterface(self): | |
| 1375 # TODO(vsm): Use typedef if / when that is supported in Dart. | |
| 1376 # Define variant as subtype. | |
| 1377 if (self._super_interface and | |
| 1378 self._interface.id is not self._super_interface): | |
| 1379 consts_emitter = self._top_level_emitter.Emit( | |
| 1380 '\n' | |
| 1381 'interface $NAME extends $BASE {\n' | |
| 1382 '$!CONSTS' | |
| 1383 '}\n', | |
| 1384 NAME=self._interface.id, | |
| 1385 BASE=self._super_interface) | |
| 1386 for const in sorted(self._interface.constants, ConstantOutputOrder): | |
| 1387 self._EmitConstant(consts_emitter, const) | |
| 1388 | |
| 1389 def AddConstant(self, constant): | |
| 1390 if (not self._super_interface or | |
| 1391 self._interface.id is self._super_interface): | |
| 1392 self._EmitConstant(self._members_emitter, constant) | |
| 1393 | |
| 1394 def _EmitConstant(self, emitter, constant): | |
| 1395 emitter.Emit('\n static final $TYPE $NAME = $VALUE;\n', | |
| 1396 NAME=constant.id, | |
| 1397 TYPE=constant.type.id, | |
| 1398 VALUE=constant.value) | |
| 1399 | |
| 1400 def AddAttribute(self, getter, setter): | |
| 1401 if getter and setter and getter.type.id == setter.type.id: | |
| 1402 self._members_emitter.Emit('\n $TYPE $NAME;\n', | |
| 1403 NAME=getter.id, TYPE=getter.type.id); | |
| 1404 return | |
| 1405 if getter and not setter: | |
| 1406 self._members_emitter.Emit('\n final $TYPE $NAME;\n', | |
| 1407 NAME=getter.id, TYPE=getter.type.id); | |
| 1408 return | |
| 1409 raise Exception('Unexpected getter/setter combination %s %s' % | |
| 1410 (getter, setter)) | |
| 1411 | |
| 1412 def AddIndexer(self, element_type): | |
| 1413 # Interface inherits all operations from List<element_type>. | |
| 1414 pass | |
| 1415 | |
| 1416 def AddOperation(self, info): | |
| 1417 """ | |
| 1418 Arguments: | |
| 1419 operations - contains the overloads, one or more operations with the same | |
| 1420 name. | |
| 1421 """ | |
| 1422 self._members_emitter.Emit('\n' | |
| 1423 ' $TYPE $NAME($PARAMS);\n', | |
| 1424 TYPE=info.type_name, | |
| 1425 NAME=info.name, | |
| 1426 PARAMS=info.ParametersInterfaceDeclaration()) | |
| 1427 | |
| 1428 # Interfaces get secondary members directly via the superinterfaces. | |
| 1429 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 1430 pass | |
| 1431 | |
| 1432 def AddSecondaryOperation(self, interface, attr): | |
| 1433 pass | |
| 1434 | |
| 1435 def AddEventAttributes(self, event_attrs): | |
| 1436 pass | |
| 1437 | |
| 1438 # Given a sorted sequence of type identifiers, return an appropriate type | |
| 1439 # name | |
| 1440 def TypeName(typeIds, interface): | |
| 1441 # Dynamically type this field for now. | |
| 1442 return 'var' | |
| 1443 | |
| 1444 # ------------------------------------------------------------------------------ | |
| 1445 | |
| 1446 # TODO(jmesserly): inheritance is probably not the right way to factor this long | |
| 1447 # term, but it makes merging better for now. | |
| 1448 class HtmlDartInterfaceGenerator(DartInterfaceGenerator): | |
| 1449 """Generates Dart Interface definition for one DOM IDL interface.""" | |
| 1450 | |
| 1451 def __init__(self, interface, emitter, template, | |
| 1452 common_prefix, super_interface, source_filter): | |
| 1453 super(HtmlDartInterfaceGenerator, self).__init__(interface, | |
| 1454 emitter, template, common_prefix, super_interface, source_filter) | |
| 1455 | |
| 1456 def AddEventAttributes(self, event_attrs): | |
| 1457 events_interface = self._interface.id + 'Events' | |
| 1458 self._members_emitter.Emit('\n $TYPE get on();\n', | |
| 1459 TYPE=events_interface) | |
| 1460 events_members = self._emitter.Emit( | |
| 1461 '\ninterface $INTERFACE {\n$!MEMBERS}\n', | |
| 1462 INTERFACE=events_interface) | |
| 1463 | |
| 1464 for getter, setter in event_attrs: | |
| 1465 event = getter or setter | |
| 1466 events_members.Emit('\n EventListenerList get $NAME();\n', NAME=event.id) | |
| 1467 | |
| 1468 | |
| 1469 # ------------------------------------------------------------------------------ | |
| 1470 | |
| 1471 class DummyInterfaceGenerator(object): | 703 class DummyInterfaceGenerator(object): |
| 1472 """Generates nothing.""" | 704 """Generates nothing.""" |
| 1473 | 705 |
| 1474 def __init__(self, system, interface): | 706 def __init__(self, system, interface): |
| 1475 pass | 707 pass |
| 1476 | 708 |
| 1477 def StartInterface(self): | 709 def StartInterface(self): |
| 1478 pass | 710 pass |
| 1479 | 711 |
| 1480 def FinishInterface(self): | 712 def FinishInterface(self): |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1562 if not interface.parents: | 794 if not interface.parents: |
| 1563 return 'DOMWrapperBase' | 795 return 'DOMWrapperBase' |
| 1564 | 796 |
| 1565 supertype = interface.parents[0].type.id | 797 supertype = interface.parents[0].type.id |
| 1566 | 798 |
| 1567 # FIXME: We're currently injecting List<..> and EventTarget as | 799 # FIXME: We're currently injecting List<..> and EventTarget as |
| 1568 # supertypes in dart.idl. We should annotate/preserve as | 800 # supertypes in dart.idl. We should annotate/preserve as |
| 1569 # attributes instead. For now, this hack lets the interfaces | 801 # attributes instead. For now, this hack lets the interfaces |
| 1570 # inherit, but not the classes. | 802 # inherit, but not the classes. |
| 1571 # List methods are injected in AddIndexer. | 803 # List methods are injected in AddIndexer. |
| 1572 if _IsDartListType(supertype) or _IsDartCollectionType(supertype): | 804 if IsDartListType(supertype) or IsDartCollectionType(supertype): |
| 1573 return 'DOMWrapperBase' | 805 return 'DOMWrapperBase' |
| 1574 | 806 |
| 1575 if supertype == 'EventTarget': | 807 if supertype == 'EventTarget': |
| 1576 # Most implementors of EventTarget specify the EventListener operations | 808 # Most implementors of EventTarget specify the EventListener operations |
| 1577 # again. If the operations are not specified, try to inherit from the | 809 # again. If the operations are not specified, try to inherit from the |
| 1578 # EventTarget implementation. | 810 # EventTarget implementation. |
| 1579 # | 811 # |
| 1580 # Applies to MessagePort. | 812 # Applies to MessagePort. |
| 1581 if not [op for op in interface.operations if op.id == 'addEventListener']: | 813 if not [op for op in interface.operations if op.id == 'addEventListener']: |
| 1582 return self._ImplClassName(supertype) | 814 return self._ImplClassName(supertype) |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1954 # that Y = Z-X, so we need to check for Y. | 1186 # that Y = Z-X, so we need to check for Y. |
| 1955 true_code = emitter.Emit( | 1187 true_code = emitter.Emit( |
| 1956 '$(INDENT)if ($COND) {\n' | 1188 '$(INDENT)if ($COND) {\n' |
| 1957 '$!TRUE' | 1189 '$!TRUE' |
| 1958 '$(INDENT)}\n', | 1190 '$(INDENT)}\n', |
| 1959 COND=test, INDENT=indent) | 1191 COND=test, INDENT=indent) |
| 1960 self.GenerateDispatch( | 1192 self.GenerateDispatch( |
| 1961 true_code, info, indent + ' ', position + 1, positive) | 1193 true_code, info, indent + ' ', position + 1, positive) |
| 1962 return True | 1194 return True |
| 1963 | 1195 |
| 1964 | |
| 1965 # ------------------------------------------------------------------------------ | |
| 1966 | |
| 1967 class FrogInterfaceGenerator(object): | |
| 1968 """Generates a Frog class for a DOM IDL interface.""" | |
| 1969 | |
| 1970 def __init__(self, system, interface, template, super_interface, dart_code): | |
| 1971 """Generates Dart code for the given interface. | |
| 1972 | |
| 1973 Args: | |
| 1974 | |
| 1975 interface: an IDLInterface instance. It is assumed that all types have | |
| 1976 been converted to Dart types (e.g. int, String), unless they are in | |
| 1977 the same package as the interface. | |
| 1978 template: A string template. | |
| 1979 super_interface: A string or None, the name of the common interface that | |
| 1980 this interface implements, if any. | |
| 1981 dart_code: an Emitter for the file containing the Dart implementation | |
| 1982 class. | |
| 1983 """ | |
| 1984 self._system = system | |
| 1985 self._interface = interface | |
| 1986 self._template = template | |
| 1987 self._super_interface = super_interface | |
| 1988 self._dart_code = dart_code | |
| 1989 self._current_secondary_parent = None | |
| 1990 | |
| 1991 | |
| 1992 def StartInterface(self): | |
| 1993 interface = self._interface | |
| 1994 interface_name = interface.id | |
| 1995 | |
| 1996 self._class_name = self._ImplClassName(interface_name) | |
| 1997 | |
| 1998 base = None | |
| 1999 if interface.parents: | |
| 2000 supertype = interface.parents[0].type.id | |
| 2001 if _IsDartCollectionType(supertype): | |
| 2002 # List methods are injected in AddIndexer. | |
| 2003 pass | |
| 2004 else: | |
| 2005 base = self._ImplClassName(supertype) | |
| 2006 | |
| 2007 if interface_name in _frog_dom_custom_native_specs: | |
| 2008 native_spec = _frog_dom_custom_native_specs[interface_name] | |
| 2009 else: | |
| 2010 # Make the class 'hidden' so it is dynamically patched at runtime. This | |
| 2011 # is useful not only for browser compat, but to allow code that links | |
| 2012 # against dart:dom to load in a worker isolate. | |
| 2013 native_spec = '*' + interface_name | |
| 2014 | |
| 2015 if base: | |
| 2016 extends = ' extends ' + base | |
| 2017 elif native_spec[0] == '=': | |
| 2018 # The implementation is a singleton with no prototype. | |
| 2019 extends = '' | |
| 2020 else: | |
| 2021 extends = ' extends _DOMTypeJs' | |
| 2022 | |
| 2023 # TODO: Include all implemented interfaces, including other Lists. | |
| 2024 implements = [interface_name] | |
| 2025 element_type = MaybeTypedArrayElementType(self._interface) | |
| 2026 if element_type: | |
| 2027 implements.append('List<' + element_type + '>') | |
| 2028 | |
| 2029 self._members_emitter = self._dart_code.Emit( | |
| 2030 self._template, | |
| 2031 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | |
| 2032 #$!MEMBERS | |
| 2033 #} | |
| 2034 CLASSNAME=self._class_name, | |
| 2035 EXTENDS=extends, | |
| 2036 IMPLEMENTS=' implements ' + ', '.join(implements), | |
| 2037 NATIVESPEC=' native "' + native_spec + '"') | |
| 2038 | |
| 2039 element_type = MaybeTypedArrayElementType(interface) | |
| 2040 if element_type: | |
| 2041 self.AddTypedArrayConstructors(element_type) | |
| 2042 | |
| 2043 | |
| 2044 def FinishInterface(self): | |
| 2045 """.""" | |
| 2046 pass | |
| 2047 | |
| 2048 def _ImplClassName(self, type_name): | |
| 2049 return '_' + type_name + 'Js' | |
| 2050 | |
| 2051 def _NarrowToImplementationType(self, type_name): | |
| 2052 # TODO(sra): Move into the 'system' and cache the result. | |
| 2053 if type_name == 'EventListener': | |
| 2054 # Callbacks are typedef functions so don't have a class. | |
| 2055 return type_name | |
| 2056 if self._system._database.HasInterface(type_name): | |
| 2057 interface = self._system._database.GetInterface(type_name) | |
| 2058 if _RecognizeCallback(interface): | |
| 2059 # Callbacks are typedef functions so don't have a class. | |
| 2060 return type_name | |
| 2061 else: | |
| 2062 return self._ImplClassName(type_name) | |
| 2063 return type_name | |
| 2064 | |
| 2065 def _NarrowInputType(self, type_name): | |
| 2066 return self._NarrowToImplementationType(type_name) | |
| 2067 | |
| 2068 def _NarrowOutputType(self, type_name): | |
| 2069 return self._NarrowToImplementationType(type_name) | |
| 2070 | |
| 2071 def AddConstant(self, constant): | |
| 2072 # Since we are currently generating native classes without interfaces, | |
| 2073 # generate the constants as part of the class. This will need to go away | |
| 2074 # if we revert back to generating interfaces. | |
| 2075 self._members_emitter.Emit('\n static final $TYPE $NAME = $VALUE;\n', | |
| 2076 NAME=constant.id, | |
| 2077 TYPE=constant.type.id, | |
| 2078 VALUE=constant.value) | |
| 2079 | |
| 2080 pass | |
| 2081 | |
| 2082 def AddAttribute(self, getter, setter): | |
| 2083 output_type = getter and self._NarrowOutputType(getter.type.id) | |
| 2084 input_type = setter and self._NarrowInputType(setter.type.id) | |
| 2085 | |
| 2086 # If the (getter, setter) pair is shadowing, we can't generate a shadowing | |
| 2087 # field (Issue 1633). | |
| 2088 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) | |
| 2089 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) | |
| 2090 if super_getter or super_setter: | |
| 2091 if getter and not setter and super_getter and not super_setter: | |
| 2092 if getter.type.id == super_getter.type.id: | |
| 2093 # Compatible getter, use the superclass property. This works because | |
| 2094 # JavaScript will do its own dynamic dispatch. | |
| 2095 self._members_emitter.Emit( | |
| 2096 '\n' | |
| 2097 ' // Use implementation from $SUPER.\n' | |
| 2098 ' // final $TYPE $NAME;\n', | |
| 2099 SUPER=super_getter_interface.id, | |
| 2100 NAME=getter.id, TYPE=output_type) | |
| 2101 return | |
| 2102 | |
| 2103 self._members_emitter.Emit('\n // Shadowing definition.') | |
| 2104 self._AddAttributeUsingProperties(getter, setter) | |
| 2105 return | |
| 2106 | |
| 2107 if getter and setter and input_type == output_type: | |
| 2108 self._members_emitter.Emit( | |
| 2109 '\n $TYPE $NAME;\n', | |
| 2110 NAME=getter.id, TYPE=output_type) | |
| 2111 return | |
| 2112 if getter and not setter: | |
| 2113 self._members_emitter.Emit( | |
| 2114 '\n final $TYPE $NAME;\n', | |
| 2115 NAME=getter.id, TYPE=output_type) | |
| 2116 return | |
| 2117 self._AddAttributeUsingProperties(getter, setter) | |
| 2118 | |
| 2119 def _AddAttributeUsingProperties(self, getter, setter): | |
| 2120 if getter: | |
| 2121 self._AddGetter(getter) | |
| 2122 if setter: | |
| 2123 self._AddSetter(setter) | |
| 2124 | |
| 2125 def _AddGetter(self, attr): | |
| 2126 # TODO(sra): Remove native body when Issue 829 fixed. | |
| 2127 self._members_emitter.Emit( | |
| 2128 '\n $TYPE get $NAME() native "return this.$NAME;";\n', | |
| 2129 NAME=attr.id, TYPE=self._NarrowOutputType(attr.type.id)) | |
| 2130 | |
| 2131 def _AddSetter(self, attr): | |
| 2132 # TODO(sra): Remove native body when Issue 829 fixed. | |
| 2133 self._members_emitter.Emit( | |
| 2134 ' void set $NAME($TYPE value) native "this.$NAME = value;";\n', | |
| 2135 NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id)) | |
| 2136 | |
| 2137 def _FindShadowedAttribute(self, attr): | |
| 2138 """Returns (attribute, superinterface) or (None, None).""" | |
| 2139 def FindInParent(interface): | |
| 2140 """Returns matching attribute in parent, or None.""" | |
| 2141 if interface.parents: | |
| 2142 parent = interface.parents[0] | |
| 2143 if _IsDartCollectionType(parent.type.id): | |
| 2144 return (None, None) | |
| 2145 if self._system._database.HasInterface(parent.type.id): | |
| 2146 parent_interface = self._system._database.GetInterface(parent.type.id) | |
| 2147 attr2 = _FindMatchingAttribute(parent_interface, attr) | |
| 2148 if attr2: | |
| 2149 return (attr2, parent_interface) | |
| 2150 return FindInParent(parent_interface) | |
| 2151 return (None, None) | |
| 2152 | |
| 2153 return FindInParent(self._interface) if attr else (None, None) | |
| 2154 | |
| 2155 | |
| 2156 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 2157 self._SecondaryContext(interface) | |
| 2158 self.AddAttribute(getter, setter) | |
| 2159 | |
| 2160 def AddSecondaryOperation(self, interface, info): | |
| 2161 self._SecondaryContext(interface) | |
| 2162 self.AddOperation(info) | |
| 2163 | |
| 2164 def AddEventAttributes(self, event_attrs): | |
| 2165 pass | |
| 2166 | |
| 2167 def _SecondaryContext(self, interface): | |
| 2168 if interface is not self._current_secondary_parent: | |
| 2169 self._current_secondary_parent = interface | |
| 2170 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) | |
| 2171 | |
| 2172 def AddIndexer(self, element_type): | |
| 2173 """Adds all the methods required to complete implementation of List.""" | |
| 2174 # We would like to simply inherit the implementation of everything except | |
| 2175 # get length(), [], and maybe []=. It is possible to extend from a base | |
| 2176 # array implementation class only when there is no other implementation | |
| 2177 # inheritance. There might be no implementation inheritance other than | |
| 2178 # DOMBaseWrapper for many classes, but there might be some where the | |
| 2179 # array-ness is introduced by a non-root interface: | |
| 2180 # | |
| 2181 # interface Y extends X, List<T> ... | |
| 2182 # | |
| 2183 # In the non-root case we have to choose between: | |
| 2184 # | |
| 2185 # class YImpl extends XImpl { add List<T> methods; } | |
| 2186 # | |
| 2187 # and | |
| 2188 # | |
| 2189 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
| 2190 # | |
| 2191 self._members_emitter.Emit( | |
| 2192 '\n' | |
| 2193 ' $TYPE operator[](int index) native "return this[index];";\n', | |
| 2194 TYPE=self._NarrowOutputType(element_type)) | |
| 2195 | |
| 2196 if 'CustomIndexedSetter' in self._interface.ext_attrs: | |
| 2197 self._members_emitter.Emit( | |
| 2198 '\n' | |
| 2199 ' void operator[]=(int index, $TYPE value) native "this[index] = valu
e";\n', | |
| 2200 TYPE=self._NarrowInputType(element_type)) | |
| 2201 else: | |
| 2202 self._members_emitter.Emit( | |
| 2203 '\n' | |
| 2204 ' void operator[]=(int index, $TYPE value) {\n' | |
| 2205 ' throw new UnsupportedOperationException("Cannot assign element of
immutable List.");\n' | |
| 2206 ' }\n', | |
| 2207 TYPE=self._NarrowInputType(element_type)) | |
| 2208 | |
| 2209 # TODO(sra): Use separate mixins for mutable implementations of List<T>. | |
| 2210 # TODO(sra): Use separate mixins for typed array implementations of List<T>. | |
| 2211 template_file = 'immutable_list_mixin.darttemplate' | |
| 2212 template = self._system._templates.Load(template_file) | |
| 2213 self._members_emitter.Emit(template, E=element_type) | |
| 2214 | |
| 2215 | |
| 2216 def AddTypedArrayConstructors(self, element_type): | |
| 2217 self._members_emitter.Emit( | |
| 2218 '\n' | |
| 2219 ' factory $CTOR(int length) => _construct_$CTOR(length);\n' | |
| 2220 '\n' | |
| 2221 ' factory $CTOR.fromList(List<$TYPE> list) => _construct_$CTOR(list);\n
' | |
| 2222 '\n' | |
| 2223 ' factory $CTOR.fromBuffer(ArrayBuffer buffer) => _construct_$CTOR(buff
er);\n' | |
| 2224 '\n' | |
| 2225 ' static _construct_$CTOR(arg) native \'return new $CTOR(arg);\';\n', | |
| 2226 CTOR=self._interface.id, | |
| 2227 TYPE=element_type) | |
| 2228 | |
| 2229 | |
| 2230 def AddOperation(self, info): | |
| 2231 """ | |
| 2232 Arguments: | |
| 2233 info: An OperationInfo object. | |
| 2234 """ | |
| 2235 # TODO(vsm): Handle overloads. | |
| 2236 self._members_emitter.Emit( | |
| 2237 '\n' | |
| 2238 ' $TYPE $NAME($PARAMS) native;\n', | |
| 2239 TYPE=self._NarrowOutputType(info.type_name), | |
| 2240 NAME=info.name, | |
| 2241 PARAMS=info.ParametersImplementationDeclaration( | |
| 2242 lambda type_name: self._NarrowInputType(type_name))) | |
| 2243 | |
| 2244 | |
| 2245 # ------------------------------------------------------------------------------ | |
| 2246 | |
| 2247 # TODO(jmesserly): inheritance is probably not the right way to factor this long | |
| 2248 # term, but it makes merging better for now. | |
| 2249 class HtmlFrogInterfaceGenerator(FrogInterfaceGenerator): | |
| 2250 """Generates a Frog class for the dart:html library from a DOM IDL | |
| 2251 interface. | |
| 2252 """ | |
| 2253 | |
| 2254 def __init__(self, system, interface, template, super_interface, dart_code): | |
| 2255 super(HtmlFrogInterfaceGenerator, self).__init__( | |
| 2256 system, interface, template, super_interface, dart_code) | |
| 2257 | |
| 2258 def AddEventAttributes(self, event_attrs): | |
| 2259 events_class = self._interface.id + 'EventsImpl' | |
| 2260 events_interface = self._interface.id + 'Events' | |
| 2261 self._members_emitter.Emit('\n $TYPE get on() =>\n new $TYPE(this);\n', | |
| 2262 TYPE=events_class) | |
| 2263 | |
| 2264 events_members = self._dart_code.Emit( | |
| 2265 '\n' | |
| 2266 'class $CLASSNAME extends EventsImplementation ' | |
| 2267 'implements $INTERFACE {\n' | |
| 2268 ' $CLASSNAME(_ptr) : super._wrap(_ptr);\n' | |
| 2269 '$!MEMBERS}\n', | |
| 2270 CLASSNAME=events_class, | |
| 2271 INTERFACE=events_interface) | |
| 2272 | |
| 2273 for getter, setter in event_attrs: | |
| 2274 event = getter or setter | |
| 2275 events_members.Emit( | |
| 2276 "\n" | |
| 2277 "EventListenerList get $NAME() => _get('$NAME');\n", | |
| 2278 NAME=event.id) | |
| 2279 | |
| 2280 | |
| 2281 # ------------------------------------------------------------------------------ | 1196 # ------------------------------------------------------------------------------ |
| 2282 | 1197 |
| 2283 class IDLTypeInfo(object): | 1198 class IDLTypeInfo(object): |
| 2284 def __init__(self, idl_type, native_type=None, ref_counted=True, | 1199 def __init__(self, idl_type, native_type=None, ref_counted=True, |
| 2285 has_dart_wrapper=True, conversion_template=None, | 1200 has_dart_wrapper=True, conversion_template=None, |
| 2286 custom_to_dart=False): | 1201 custom_to_dart=False): |
| 2287 self._idl_type = idl_type | 1202 self._idl_type = idl_type |
| 2288 self._native_type = native_type | 1203 self._native_type = native_type |
| 2289 self._ref_counted = ref_counted | 1204 self._ref_counted = ref_counted |
| 2290 self._has_dart_wrapper = has_dart_wrapper | 1205 self._has_dart_wrapper = has_dart_wrapper |
| (...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3166 namespace = 'HTMLNames' | 2081 namespace = 'HTMLNames' |
| 3167 svg_exceptions = ['class', 'id', 'onabort', 'onclick', 'onerror', 'onload', | 2082 svg_exceptions = ['class', 'id', 'onabort', 'onclick', 'onerror', 'onload', |
| 3168 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', | 2083 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', |
| 3169 'onmouseup', 'onresize', 'onscroll', 'onunload'] | 2084 'onmouseup', 'onresize', 'onscroll', 'onunload'] |
| 3170 if self._interface.id.startswith('SVG') and not attr.id in svg_exceptions: | 2085 if self._interface.id.startswith('SVG') and not attr.id in svg_exceptions: |
| 3171 namespace = 'SVGNames' | 2086 namespace = 'SVGNames' |
| 3172 self._cpp_impl_includes[namespace] = 1 | 2087 self._cpp_impl_includes[namespace] = 1 |
| 3173 | 2088 |
| 3174 attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower() | 2089 attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower() |
| 3175 return 'WebCore::%s::%sAttr' % (namespace, attribute_name) | 2090 return 'WebCore::%s::%sAttr' % (namespace, attribute_name) |
| OLD | NEW |