Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: client/dom/scripts/dartgenerator.py

Issue 9403004: Wrapperless dart:html generator (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review fixes Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698