OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
3 # for details. All rights reserved. Use of this source code is governed by a | 3 # for details. All rights reserved. Use of this source code is governed by a |
4 # BSD-style license that can be found in the LICENSE file. | 4 # BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 """This module provides shared functionality for the system to generate | 6 """This module provides shared functionality for the system to generate |
7 Dart:html APIs from the IDL database.""" | 7 Dart:html APIs from the IDL database.""" |
8 | 8 |
9 import emitter | 9 import emitter |
10 import os | 10 import os |
(...skipping 29 matching lines...) Expand all Loading... |
40 'Url.revokeObjectURL', | 40 'Url.revokeObjectURL', |
41 'WheelEvent.wheelDeltaX', | 41 'WheelEvent.wheelDeltaX', |
42 'WheelEvent.wheelDeltaY', | 42 'WheelEvent.wheelDeltaY', |
43 ]) | 43 ]) |
44 | 44 |
45 | 45 |
46 # Classes that offer only static methods, and therefore we should suppress | 46 # Classes that offer only static methods, and therefore we should suppress |
47 # constructor creation. | 47 # constructor creation. |
48 _static_classes = set(['Url']) | 48 _static_classes = set(['Url']) |
49 | 49 |
50 # Types that are accessible cross-frame in a limited fashion. | |
51 # In these cases, the base type (e.g., Window) provides restricted access | |
52 # while the subtype (e.g., LocalWindow) provides full access to the | |
53 # corresponding objects if there are from the same frame. | |
54 _secure_base_types = { | |
55 'LocalWindow': 'Window', | |
56 'LocalLocation': 'Location', | |
57 'LocalHistory': 'History', | |
58 } | |
59 | |
60 def SecureOutputType(generator, type_name, is_dart_type=False): | |
61 if is_dart_type: | |
62 dart_name = type_name | |
63 else: | |
64 dart_name = generator._DartType(type_name) | |
65 # We only need to secure Window. Only local History and Location are returned | |
66 # in generated code. | |
67 if dart_name == 'LocalWindow': | |
68 return _secure_base_types[dart_name] | |
69 return dart_name | |
70 | |
71 # Information for generating element constructors. | 50 # Information for generating element constructors. |
72 # | 51 # |
73 # TODO(sra): maybe remove all the argument complexity and use cascades. | 52 # TODO(sra): maybe remove all the argument complexity and use cascades. |
74 # | 53 # |
75 # var c = new CanvasElement(width: 100, height: 70); | 54 # var c = new CanvasElement(width: 100, height: 70); |
76 # var c = new CanvasElement()..width = 100..height = 70; | 55 # var c = new CanvasElement()..width = 100..height = 70; |
77 # | 56 # |
78 class ElementConstructorInfo(object): | 57 class ElementConstructorInfo(object): |
79 def __init__(self, name=None, tag=None, | 58 def __init__(self, name=None, tag=None, |
80 params=[], opt_params=[], | 59 params=[], opt_params=[], |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 | 185 |
207 class HtmlDartInterfaceGenerator(object): | 186 class HtmlDartInterfaceGenerator(object): |
208 """Generates dart interface and implementation for the DOM IDL interface.""" | 187 """Generates dart interface and implementation for the DOM IDL interface.""" |
209 | 188 |
210 def __init__(self, options, library_emitter, event_generator, interface, | 189 def __init__(self, options, library_emitter, event_generator, interface, |
211 backend): | 190 backend): |
212 self._renamer = options.renamer | 191 self._renamer = options.renamer |
213 self._database = options.database | 192 self._database = options.database |
214 self._template_loader = options.templates | 193 self._template_loader = options.templates |
215 self._type_registry = options.type_registry | 194 self._type_registry = options.type_registry |
| 195 self._options = options |
216 self._library_emitter = library_emitter | 196 self._library_emitter = library_emitter |
217 self._event_generator = event_generator | 197 self._event_generator = event_generator |
218 self._interface = interface | 198 self._interface = interface |
219 self._backend = backend | 199 self._backend = backend |
220 self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) | 200 self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) |
221 | 201 |
222 def Generate(self): | 202 def Generate(self): |
223 if 'Callback' in self._interface.ext_attrs: | 203 if 'Callback' in self._interface.ext_attrs: |
224 self.GenerateCallback() | 204 self.GenerateCallback() |
225 else: | 205 else: |
226 self.GenerateInterface() | 206 self.GenerateInterface() |
227 | 207 |
228 def GenerateCallback(self): | 208 def GenerateCallback(self): |
229 """Generates a typedef for the callback interface.""" | 209 """Generates a typedef for the callback interface.""" |
230 handlers = [operation for operation in self._interface.operations | 210 handlers = [operation for operation in self._interface.operations |
231 if operation.id == 'handleEvent'] | 211 if operation.id == 'handleEvent'] |
232 info = AnalyzeOperation(self._interface, handlers) | 212 info = AnalyzeOperation(self._interface, handlers) |
233 code = self._library_emitter.FileEmitter(self._interface.id) | 213 code = self._library_emitter.FileEmitter(self._interface.id) |
234 code.Emit(self._template_loader.Load('callback.darttemplate')) | 214 code.Emit(self._template_loader.Load('callback.darttemplate')) |
235 code.Emit('typedef void $NAME($PARAMS);\n', | 215 code.Emit('typedef void $NAME($PARAMS);\n', |
236 NAME=self._interface.id, | 216 NAME=self._interface.id, |
237 PARAMS=info.ParametersDeclaration(self._DartType)) | 217 PARAMS=info.ParametersDeclaration(self._DartType)) |
238 self._backend.GenerateCallback(info) | 218 self._backend.GenerateCallback(info) |
239 | 219 |
240 def GenerateInterface(self): | 220 def GenerateInterface(self): |
241 interface_name = self._interface_type_info.interface_name() | 221 interface_name = self._interface_type_info.interface_name() |
242 | 222 |
243 # TODO: this is just tossing the interface, need to skip it completely. | |
244 interface_emitter = emitter.Emitter() | |
245 | |
246 template_file = 'interface_%s.darttemplate' % interface_name | |
247 interface_template = (self._template_loader.TryLoad(template_file) or | |
248 self._template_loader.Load('interface.darttemplate')) | |
249 | |
250 implements = [] | |
251 for parent in self._interface.parents: | |
252 parent_type_info = self._type_registry.TypeInfo(parent.type.id) | |
253 implements.append(parent_type_info.interface_name()) | |
254 | |
255 if self._interface_type_info.list_item_type(): | |
256 item_type_info = self._type_registry.TypeInfo( | |
257 self._interface_type_info.list_item_type()) | |
258 implements.append('List<%s>' % item_type_info.dart_type()) | |
259 | |
260 if interface_name in _secure_base_types: | |
261 implements.append(_secure_base_types[interface_name]) | |
262 | |
263 comment = ' extends' | |
264 implements_str = '' | |
265 if implements: | |
266 implements_str += ' implements ' + ', '.join(implements) | |
267 comment = ',' | |
268 | |
269 factory_provider = None | 223 factory_provider = None |
270 if interface_name in interface_factories: | 224 if interface_name in interface_factories: |
271 factory_provider = interface_factories[interface_name] | 225 factory_provider = interface_factories[interface_name] |
272 | 226 |
273 constructors = [] | 227 constructors = [] |
274 if interface_name in _static_classes: | 228 if interface_name in _static_classes: |
275 constructor_info = None | 229 constructor_info = None |
276 else: | 230 else: |
277 constructor_info = AnalyzeConstructor(self._interface) | 231 constructor_info = AnalyzeConstructor(self._interface) |
278 if constructor_info: | 232 if constructor_info: |
(...skipping 15 matching lines...) Expand all Loading... |
294 self._interface_type_info.implementation_name(), | 248 self._interface_type_info.implementation_name(), |
295 self._DartType) | 249 self._DartType) |
296 | 250 |
297 for info in infos: | 251 for info in infos: |
298 constructors.append(info.ConstructorInfo(self._interface.id)) | 252 constructors.append(info.ConstructorInfo(self._interface.id)) |
299 if factory_provider: | 253 if factory_provider: |
300 assert factory_provider == info.factory_provider_name | 254 assert factory_provider == info.factory_provider_name |
301 else: | 255 else: |
302 factory_provider = info.factory_provider_name | 256 factory_provider = info.factory_provider_name |
303 | 257 |
304 # TODO(vsm): Add appropriate package / namespace syntax. | |
305 (self._type_comment_emitter, | |
306 self._members_emitter, | |
307 self._top_level_emitter) = interface_emitter.Emit( | |
308 interface_template + '$!TOP_LEVEL', | |
309 ID='_I%s' % interface_name, | |
310 EXTENDS=implements_str) | |
311 | |
312 implementation_emitter = self._ImplementationEmitter() | 258 implementation_emitter = self._ImplementationEmitter() |
313 | 259 |
314 base_type_info = None | 260 base_type_info = None |
315 if self._interface.parents: | 261 if self._interface.parents: |
316 supertype = self._interface.parents[0].type.id | 262 supertype = self._interface.parents[0].type.id |
317 if not IsDartCollectionType(supertype) and not IsPureInterface(supertype): | 263 if not IsDartCollectionType(supertype) and not IsPureInterface(supertype): |
318 base_type_info = self._type_registry.TypeInfo(supertype) | 264 base_type_info = self._type_registry.TypeInfo(supertype) |
319 if base_type_info.merged_into() \ | 265 if base_type_info.merged_into() \ |
320 and self._backend.ImplementsMergedMembers(): | 266 and self._backend.ImplementsMergedMembers(): |
321 base_type_info = self._type_registry.TypeInfo( | 267 base_type_info = self._type_registry.TypeInfo( |
322 base_type_info.merged_into()) | 268 base_type_info.merged_into()) |
323 | 269 |
324 if base_type_info: | 270 if base_type_info: |
325 base_class = base_type_info.implementation_name() | 271 base_class = base_type_info.implementation_name() |
326 else: | 272 else: |
327 base_class = self._backend.RootClassName() | 273 base_class = self._backend.RootClassName() |
328 | 274 |
329 implements = self._backend.AdditionalImplementedInterfaces() | 275 implements = self._backend.AdditionalImplementedInterfaces() |
330 for parent in self._interface.parents: | 276 for parent in self._interface.parents: |
331 parent_type_info = self._type_registry.TypeInfo(parent.type.id) | 277 parent_type_info = self._type_registry.TypeInfo(parent.type.id) |
332 if parent_type_info != base_type_info: | 278 if parent_type_info != base_type_info: |
333 implements.append(parent_type_info.interface_name()) | 279 implements.append(parent_type_info.interface_name()) |
334 | 280 |
335 if interface_name in _secure_base_types: | 281 secure_base_name = self._backend.SecureBaseName(interface_name) |
336 implements.append(_secure_base_types[interface_name]) | 282 if secure_base_name: |
| 283 implements.append(secure_base_name) |
337 | 284 |
338 implements_str = '' | 285 implements_str = '' |
339 if implements: | 286 if implements: |
340 implements_str = ' implements ' + ', '.join(set(implements)) | 287 implements_str = ' implements ' + ', '.join(set(implements)) |
341 | 288 |
342 self._implementation_members_emitter = implementation_emitter.Emit( | 289 self._implementation_members_emitter = implementation_emitter.Emit( |
343 self._backend.ImplementationTemplate(), | 290 self._backend.ImplementationTemplate(), |
344 CLASSNAME=self._interface_type_info.implementation_name(), | 291 CLASSNAME=self._interface_type_info.implementation_name(), |
345 EXTENDS=' extends %s' % base_class if base_class else '', | 292 EXTENDS=' extends %s' % base_class if base_class else '', |
346 IMPLEMENTS=implements_str, | 293 IMPLEMENTS=implements_str, |
347 DOMNAME=self._interface.doc_js_name, | 294 DOMNAME=self._interface.doc_js_name, |
348 NATIVESPEC=self._backend.NativeSpec()) | 295 NATIVESPEC=self._backend.NativeSpec()) |
349 self._backend.StartInterface(self._implementation_members_emitter) | 296 self._backend.StartInterface(self._implementation_members_emitter) |
350 | 297 |
351 for constructor_info in constructors: | |
352 constructor_info.GenerateFactoryInvocation( | |
353 self._DartType, self._members_emitter, factory_provider) | |
354 | |
355 self._backend.AddConstructors(constructors, factory_provider, | 298 self._backend.AddConstructors(constructors, factory_provider, |
356 self._interface_type_info.implementation_name(), | 299 self._interface_type_info.implementation_name(), |
357 base_class) | 300 base_class) |
358 | 301 |
359 typed_array_type = None | 302 events_class_name = self._event_generator.ProcessInterface( |
360 for interface in self._database.Hierarchy(self._interface): | |
361 type_info = self._type_registry.TypeInfo(interface.id) | |
362 if type_info.is_typed_array(): | |
363 typed_array_type = type_info.list_item_type() | |
364 break | |
365 if typed_array_type: | |
366 self._members_emitter.Emit( | |
367 '\n' | |
368 ' factory $CTOR(int length) =>\n' | |
369 ' $FACTORY.create$(CTOR)(length);\n' | |
370 '\n' | |
371 ' factory $CTOR.fromList(List<$TYPE> list) =>\n' | |
372 ' $FACTORY.create$(CTOR)_fromList(list);\n' | |
373 '\n' | |
374 ' factory $CTOR.fromBuffer(ArrayBuffer buffer, [int byteOffset, int l
ength]) => \n' | |
375 ' $FACTORY.create$(CTOR)_fromBuffer(buffer, byteOffset, length);\n'
, | |
376 CTOR=self._interface.id, | |
377 TYPE=self._DartType(typed_array_type), | |
378 FACTORY=factory_provider) | |
379 | |
380 events_interface = self._event_generator.ProcessInterface( | |
381 self._interface, interface_name, | 303 self._interface, interface_name, |
382 self._backend.CustomJSMembers(), | 304 self._backend.CustomJSMembers(), |
383 interface_emitter, implementation_emitter) | 305 implementation_emitter) |
384 if events_interface: | 306 if events_class_name: |
385 self._EmitEventGetter(events_interface, events_interface) | 307 self._backend.EmitEventGetter(events_class_name) |
386 | 308 |
387 old_backend = self._backend | |
388 if not self._backend.ImplementsMergedMembers(): | |
389 self._backend = HtmlGeneratorDummyBackend() | |
390 merged_interface = self._interface_type_info.merged_interface() | 309 merged_interface = self._interface_type_info.merged_interface() |
391 if merged_interface: | 310 if merged_interface: |
392 self.AddMembers(self._database.GetInterface(merged_interface)) | 311 self._backend.AddMembers(self._database.GetInterface(merged_interface), |
393 self._backend = old_backend | 312 not self._backend.ImplementsMergedMembers()) |
394 | 313 |
395 self.AddMembers(self._interface) | 314 self._backend.AddMembers(self._interface) |
396 if merged_interface and not self._backend.ImplementsMergedMembers(): | 315 self._backend.AddSecondaryMembers(self._interface) |
397 self.AddMembers(self._database.GetInterface(merged_interface), True) | |
398 | |
399 self.AddSecondaryMembers(self._interface) | |
400 self._backend.FinishInterface() | 316 self._backend.FinishInterface() |
401 | 317 |
402 def AddMembers(self, interface, declare_only=False): | |
403 for const in sorted(interface.constants, ConstantOutputOrder): | |
404 self.AddConstant(const) | |
405 | |
406 for attr in sorted(interface.attributes, ConstantOutputOrder): | |
407 if attr.type.id != 'EventListener': | |
408 self.AddAttribute(attr, False, declare_only) | |
409 | |
410 # The implementation should define an indexer if the interface directly | |
411 # extends List. | |
412 element_type = None | |
413 requires_indexer = False | |
414 if self._interface_type_info.list_item_type(): | |
415 self.AddIndexer(self._interface_type_info.list_item_type()) | |
416 else: | |
417 for parent in self._database.Hierarchy(self._interface): | |
418 if parent == self._interface: | |
419 continue | |
420 parent_type_info = self._type_registry.TypeInfo(parent.id) | |
421 if parent_type_info.list_item_type(): | |
422 self.AmendIndexer(parent_type_info.list_item_type()) | |
423 break | |
424 | |
425 # Group overloaded operations by id | |
426 operationsById = {} | |
427 for operation in interface.operations: | |
428 if operation.id not in operationsById: | |
429 operationsById[operation.id] = [] | |
430 operationsById[operation.id].append(operation) | |
431 | |
432 # Generate operations | |
433 for id in sorted(operationsById.keys()): | |
434 operations = operationsById[id] | |
435 info = AnalyzeOperation(interface, operations) | |
436 self.AddOperation(info, False, declare_only) | |
437 | |
438 def AddSecondaryMembers(self, interface): | |
439 # With multiple inheritance, attributes and operations of non-first | |
440 # interfaces need to be added. Sometimes the attribute or operation is | |
441 # defined in the current interface as well as a parent. In that case we | |
442 # avoid making a duplicate definition and pray that the signatures match. | |
443 secondary_parents = self._TransitiveSecondaryParents(interface) | |
444 for parent_interface in sorted(secondary_parents): | |
445 if isinstance(parent_interface, str): # IsDartCollectionType(parent_inter
face) | |
446 continue | |
447 for attr in sorted(parent_interface.attributes, ConstantOutputOrder): | |
448 if not FindMatchingAttribute(interface, attr): | |
449 self.AddSecondaryAttribute(parent_interface, attr) | |
450 | |
451 # Group overloaded operations by id | |
452 operationsById = {} | |
453 for operation in parent_interface.operations: | |
454 if operation.id not in operationsById: | |
455 operationsById[operation.id] = [] | |
456 operationsById[operation.id].append(operation) | |
457 | |
458 # Generate operations | |
459 for id in sorted(operationsById.keys()): | |
460 if not any(op.id == id for op in interface.operations): | |
461 operations = operationsById[id] | |
462 info = AnalyzeOperation(interface, operations) | |
463 self.AddSecondaryOperation(parent_interface, info) | |
464 | |
465 def AddIndexer(self, element_type): | |
466 self._backend.AddIndexer(element_type) | |
467 | |
468 def AmendIndexer(self, element_type): | |
469 self._backend.AmendIndexer(element_type) | |
470 | |
471 def AddAttribute(self, attribute, is_secondary=False, declare_only=False): | |
472 dom_name = DartDomNameOfAttribute(attribute) | |
473 html_name = self._renamer.RenameMember( | |
474 self._interface.id, attribute, dom_name, 'get:') | |
475 if not html_name or self._IsPrivate(html_name): | |
476 return | |
477 | |
478 | |
479 html_setter_name = self._renamer.RenameMember( | |
480 self._interface.id, attribute, dom_name, 'set:') | |
481 read_only = (attribute.is_read_only or 'Replaceable' in attribute.ext_attrs | |
482 or not html_setter_name) | |
483 | |
484 # We don't yet handle inconsistent renames of the getter and setter yet. | |
485 assert(not html_setter_name or html_name == html_setter_name) | |
486 | |
487 if not is_secondary: | |
488 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', | |
489 DOMINTERFACE=attribute.doc_js_interface_name, | |
490 DOMNAME=dom_name) | |
491 if read_only: | |
492 template = '\n $TYPE get $NAME;\n' | |
493 else: | |
494 template = '\n $TYPE $NAME;\n' | |
495 | |
496 self._members_emitter.Emit(template, | |
497 NAME=html_name, | |
498 TYPE=SecureOutputType(self, attribute.type.id)) | |
499 | |
500 if declare_only: | |
501 self._backend.DeclareAttribute(attribute, | |
502 SecureOutputType(self, attribute.type.id), html_name, read_only) | |
503 else: | |
504 self._backend.AddAttribute(attribute, html_name, read_only) | |
505 | |
506 def AddSecondaryAttribute(self, interface, attribute): | |
507 self._backend.SecondaryContext(interface) | |
508 self.AddAttribute(attribute, True) | |
509 | |
510 def AddOperation(self, info, skip_declaration=False, declare_only=False): | |
511 """ | |
512 Arguments: | |
513 operations - contains the overloads, one or more operations with the same | |
514 name. | |
515 """ | |
516 # FIXME: When we pass in operations[0] below, we're assuming all | |
517 # overloaded operations have the same security attributes. This | |
518 # is currently true, but we should consider filtering earlier or | |
519 # merging the relevant data into info itself. | |
520 html_name = self._renamer.RenameMember(self._interface.id, | |
521 info.operations[0], | |
522 info.name) | |
523 if not html_name: | |
524 if info.name == 'item': | |
525 # FIXME: item should be renamed to operator[], not removed. | |
526 self._backend.AddOperation(info, '_item') | |
527 return | |
528 | |
529 if not self._IsPrivate(html_name) and not skip_declaration: | |
530 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', | |
531 DOMINTERFACE=info.overloads[0].doc_js_interface_name, | |
532 DOMNAME=info.name) | |
533 | |
534 if info.IsStatic(): | |
535 # FIXME: provide a type. | |
536 self._members_emitter.Emit( | |
537 '\n' | |
538 ' static final $NAME = $IMPL_CLASS_NAME.$NAME;\n', | |
539 IMPL_CLASS_NAME=self._interface_type_info.implementation_name(), | |
540 NAME=html_name) | |
541 else: | |
542 self._members_emitter.Emit( | |
543 '\n' | |
544 ' $TYPE $NAME($PARAMS);\n', | |
545 TYPE=SecureOutputType(self, info.type_name), | |
546 NAME=html_name, | |
547 PARAMS=info.ParametersDeclaration(self._DartType)) | |
548 if declare_only: | |
549 self._backend.DeclareOperation(info, | |
550 SecureOutputType(self, info.type_name), html_name) | |
551 else: | |
552 self._backend.AddOperation(info, html_name) | |
553 | |
554 def AddSecondaryOperation(self, interface, info): | |
555 self._backend.SecondaryContext(interface) | |
556 self.AddOperation(info) | |
557 | |
558 def AddConstant(self, constant): | |
559 type = TypeOrNothing(self._DartType(constant.type.id), constant.type.id) | |
560 self._members_emitter.Emit('\n static const $TYPE$NAME = $VALUE;\n', | |
561 NAME=constant.id, | |
562 TYPE=type, | |
563 VALUE=constant.value) | |
564 | |
565 self._backend.AddConstant(constant) | |
566 | |
567 def _ImplementationEmitter(self): | 318 def _ImplementationEmitter(self): |
568 basename = self._interface_type_info.implementation_name() | 319 basename = self._interface_type_info.implementation_name() |
569 if (self._interface_type_info.merged_into() and | 320 if (self._interface_type_info.merged_into() and |
570 self._backend.ImplementsMergedMembers()): | 321 self._backend.ImplementsMergedMembers()): |
571 # Merged members are implemented in target interface implementation. | 322 # Merged members are implemented in target interface implementation. |
572 return emitter.Emitter() | 323 return emitter.Emitter() |
573 return self._library_emitter.FileEmitter(basename) | 324 return self._library_emitter.FileEmitter(basename) |
574 | 325 |
575 def _EmitEventGetter(self, events_interface, events_class): | |
576 self._members_emitter.Emit( | |
577 '\n /**' | |
578 '\n * @domName EventTarget.addEventListener, ' | |
579 'EventTarget.removeEventListener, EventTarget.dispatchEvent' | |
580 '\n */' | |
581 '\n $TYPE get on;\n', | |
582 TYPE=events_interface) | |
583 | |
584 self._implementation_members_emitter.Emit( | |
585 '\n /**' | |
586 '\n * @domName EventTarget.addEventListener, ' | |
587 'EventTarget.removeEventListener, EventTarget.dispatchEvent' | |
588 '\n */' | |
589 '\n $TYPE get on =>\n new $TYPE(this);\n', | |
590 TYPE=events_class) | |
591 | |
592 def _TransitiveSecondaryParents(self, interface): | |
593 """Returns a list of all non-primary parents. | |
594 | |
595 The list contains the interface objects for interfaces defined in the | |
596 database, and the name for undefined interfaces. | |
597 """ | |
598 def walk(parents): | |
599 for parent in parents: | |
600 parent_name = parent.type.id | |
601 if parent_name == 'EventTarget': | |
602 # Currently EventTarget is implemented as a mixin, not a proper | |
603 # super interface---ignore its members. | |
604 continue | |
605 if IsDartCollectionType(parent_name): | |
606 result.append(parent_name) | |
607 continue | |
608 if self._database.HasInterface(parent_name): | |
609 parent_interface = self._database.GetInterface(parent_name) | |
610 result.append(parent_interface) | |
611 walk(parent_interface.parents) | |
612 | |
613 result = [] | |
614 if interface.parents: | |
615 parent = interface.parents[0] | |
616 if IsPureInterface(parent.type.id): | |
617 walk(interface.parents) | |
618 else: | |
619 walk(interface.parents[1:]) | |
620 return result | |
621 | |
622 def _DartType(self, type_name): | 326 def _DartType(self, type_name): |
623 return self._type_registry.DartType(type_name) | 327 return self._type_registry.DartType(type_name) |
624 | 328 |
625 def _IsPrivate(self, name): | |
626 return name.startswith('_') | |
627 | |
628 | |
629 class HtmlGeneratorDummyBackend(object): | |
630 def AddAttribute(self, attribute, html_name, read_only): | |
631 pass | |
632 | |
633 def AddOperation(self, info, html_name): | |
634 pass | |
635 | |
636 | 329 |
637 # ------------------------------------------------------------------------------ | 330 # ------------------------------------------------------------------------------ |
638 | 331 |
639 class Dart2JSBackend(HtmlDartGenerator): | 332 class Dart2JSBackend(HtmlDartGenerator): |
640 """Generates a dart2js class for the dart:html library from a DOM IDL | 333 """Generates a dart2js class for the dart:html library from a DOM IDL |
641 interface. | 334 interface. |
642 """ | 335 """ |
643 | 336 |
644 def __init__(self, interface, options): | 337 def __init__(self, interface, options): |
645 super(Dart2JSBackend, self).__init__(interface, options) | 338 super(Dart2JSBackend, self).__init__(interface, options) |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
725 # | 418 # |
726 # class YImpl extends XImpl { add List<T> methods; } | 419 # class YImpl extends XImpl { add List<T> methods; } |
727 # | 420 # |
728 # and | 421 # and |
729 # | 422 # |
730 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | 423 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } |
731 # | 424 # |
732 self._members_emitter.Emit( | 425 self._members_emitter.Emit( |
733 '\n' | 426 '\n' |
734 ' $TYPE operator[](int index) => JS("$TYPE", "#[#]", this, index);\n', | 427 ' $TYPE operator[](int index) => JS("$TYPE", "#[#]", this, index);\n', |
735 TYPE=self._NarrowOutputType(element_type)) | 428 TYPE=self.SecureOutputType(element_type)) |
736 | 429 |
737 if 'CustomIndexedSetter' in self._interface.ext_attrs: | 430 if 'CustomIndexedSetter' in self._interface.ext_attrs: |
738 self._members_emitter.Emit( | 431 self._members_emitter.Emit( |
739 '\n' | 432 '\n' |
740 ' void operator[]=(int index, $TYPE value) =>' | 433 ' void operator[]=(int index, $TYPE value) =>' |
741 ' JS("void", "#[#] = #", this, index, value);\n', | 434 ' JS("void", "#[#] = #", this, index, value);\n', |
742 TYPE=self._NarrowInputType(element_type)) | 435 TYPE=self._NarrowInputType(element_type)) |
743 else: | 436 else: |
744 # The HTML library implementation of NodeList has a custom indexed setter | 437 # The HTML library implementation of NodeList has a custom indexed setter |
745 # implementation that uses the parent node the NodeList is associated | 438 # implementation that uses the parent node the NodeList is associated |
746 # with if one is available. | 439 # with if one is available. |
747 if self._interface.id != 'NodeList': | 440 if self._interface.id != 'NodeList': |
748 self._members_emitter.Emit( | 441 self._members_emitter.Emit( |
749 '\n' | 442 '\n' |
750 ' void operator[]=(int index, $TYPE value) {\n' | 443 ' void operator[]=(int index, $TYPE value) {\n' |
751 ' throw new UnsupportedError("Cannot assign element of immutable
List.");\n' | 444 ' throw new UnsupportedError("Cannot assign element of immutable
List.");\n' |
752 ' }\n', | 445 ' }\n', |
753 TYPE=self._NarrowInputType(element_type)) | 446 TYPE=self._NarrowInputType(element_type)) |
754 | 447 |
755 # TODO(sra): Use separate mixins for mutable implementations of List<T>. | 448 # TODO(sra): Use separate mixins for mutable implementations of List<T>. |
756 # TODO(sra): Use separate mixins for typed array implementations of List<T>. | 449 # TODO(sra): Use separate mixins for typed array implementations of List<T>. |
757 if self._interface.id != 'NodeList': | 450 if self._interface.id != 'NodeList': |
758 template_file = 'immutable_list_mixin.darttemplate' | 451 template_file = 'immutable_list_mixin.darttemplate' |
759 has_contains = any(op.id == 'contains' for op in self._interface.operation
s) | 452 has_contains = any(op.id == 'contains' for op in self._interface.operation
s) |
760 template = self._template_loader.Load( | 453 template = self._template_loader.Load( |
761 template_file, | 454 template_file, |
762 {'DEFINE_CONTAINS': not has_contains}) | 455 {'DEFINE_CONTAINS': not has_contains}) |
763 self._members_emitter.Emit(template, E=self._DartType(element_type)) | 456 self._members_emitter.Emit(template, E=self._DartType(element_type)) |
764 | 457 |
765 def AddAttribute(self, attribute, html_name, read_only): | 458 def EmitAttribute(self, attribute, html_name, read_only): |
766 if self._HasCustomImplementation(attribute.id): | 459 if self._HasCustomImplementation(attribute.id): |
767 return | 460 return |
768 | 461 |
769 if IsPureInterface(self._interface.id): | 462 if IsPureInterface(self._interface.id): |
770 self._AddInterfaceAttribute(attribute) | 463 self._AddInterfaceAttribute(attribute) |
771 return | 464 return |
772 | 465 |
773 if attribute.id != html_name: | 466 if attribute.id != html_name: |
774 self._AddAttributeUsingProperties(attribute, html_name, read_only) | 467 self._AddAttributeUsingProperties(attribute, html_name, read_only) |
775 return | 468 return |
(...skipping 10 matching lines...) Expand all Loading... |
786 if read_only: | 479 if read_only: |
787 if attribute.type.id == super_attribute.type.id: | 480 if attribute.type.id == super_attribute.type.id: |
788 # Compatible attribute, use the superclass property. This works | 481 # Compatible attribute, use the superclass property. This works |
789 # because JavaScript will do its own dynamic dispatch. | 482 # because JavaScript will do its own dynamic dispatch. |
790 self._members_emitter.Emit( | 483 self._members_emitter.Emit( |
791 '\n' | 484 '\n' |
792 ' // Use implementation from $SUPER.\n' | 485 ' // Use implementation from $SUPER.\n' |
793 ' // final $TYPE $NAME;\n', | 486 ' // final $TYPE $NAME;\n', |
794 SUPER=super_attribute_interface, | 487 SUPER=super_attribute_interface, |
795 NAME=DartDomNameOfAttribute(attribute), | 488 NAME=DartDomNameOfAttribute(attribute), |
796 TYPE=self._NarrowOutputType(attribute.type.id)) | 489 TYPE=self.SecureOutputType(attribute.type.id)) |
797 return | 490 return |
798 self._members_emitter.Emit('\n // Shadowing definition.') | 491 self._members_emitter.Emit('\n // Shadowing definition.') |
799 self._AddAttributeUsingProperties(attribute, html_name, read_only) | 492 self._AddAttributeUsingProperties(attribute, html_name, read_only) |
800 return | 493 return |
801 | 494 |
802 # If the type has a conversion we need a getter or setter to contain the | 495 # If the type has a conversion we need a getter or setter to contain the |
803 # conversion code. | 496 # conversion code. |
804 if (self._OutputConversion(attribute.type.id, attribute.id) or | 497 if (self._OutputConversion(attribute.type.id, attribute.id) or |
805 self._InputConversion(attribute.type.id, attribute.id)): | 498 self._InputConversion(attribute.type.id, attribute.id)): |
806 self._AddAttributeUsingProperties(attribute, html_name, read_only) | 499 self._AddAttributeUsingProperties(attribute, html_name, read_only) |
807 return | 500 return |
808 | 501 |
809 output_type = self._NarrowOutputType(attribute.type.id) | 502 output_type = self.SecureOutputType(attribute.type.id) |
810 input_type = self._NarrowInputType(attribute.type.id) | 503 input_type = self._NarrowInputType(attribute.type.id) |
811 self.EmitAttributeDocumentation(attribute) | 504 self.EmitAttributeDocumentation(attribute) |
812 if not read_only: | 505 if not read_only: |
813 self._members_emitter.Emit( | 506 self._members_emitter.Emit( |
814 '\n $TYPE $NAME;' | 507 '\n $TYPE $NAME;' |
815 '\n', | 508 '\n', |
816 NAME=DartDomNameOfAttribute(attribute), | 509 NAME=DartDomNameOfAttribute(attribute), |
817 TYPE=output_type) | 510 TYPE=output_type) |
818 else: | 511 else: |
819 self._members_emitter.Emit( | 512 self._members_emitter.Emit( |
820 '\n final $TYPE $NAME;' | 513 '\n final $TYPE $NAME;' |
821 '\n', | 514 '\n', |
822 NAME=DartDomNameOfAttribute(attribute), | 515 NAME=DartDomNameOfAttribute(attribute), |
823 TYPE=output_type) | 516 TYPE=output_type) |
824 | 517 |
825 def _AddAttributeUsingProperties(self, attribute, html_name, read_only): | 518 def _AddAttributeUsingProperties(self, attribute, html_name, read_only): |
826 self._AddRenamingGetter(attribute, html_name) | 519 self._AddRenamingGetter(attribute, html_name) |
827 if not read_only: | 520 if not read_only: |
828 self._AddRenamingSetter(attribute, html_name) | 521 self._AddRenamingSetter(attribute, html_name) |
829 | 522 |
830 def _AddInterfaceAttribute(self, attribute): | 523 def _AddInterfaceAttribute(self, attribute): |
831 self._members_emitter.Emit( | 524 self._members_emitter.Emit( |
832 '\n $TYPE $NAME;' | 525 '\n $TYPE $NAME;' |
833 '\n', | 526 '\n', |
834 NAME=DartDomNameOfAttribute(attribute), | 527 NAME=DartDomNameOfAttribute(attribute), |
835 TYPE=self._NarrowOutputType(attribute.type.id)) | 528 TYPE=self.SecureOutputType(attribute.type.id)) |
836 | 529 |
837 def _AddRenamingGetter(self, attr, html_name): | 530 def _AddRenamingGetter(self, attr, html_name): |
838 self.EmitAttributeDocumentation(attr) | 531 self.EmitAttributeDocumentation(attr) |
839 | 532 |
840 conversion = self._OutputConversion(attr.type.id, attr.id) | 533 conversion = self._OutputConversion(attr.type.id, attr.id) |
841 if conversion: | 534 if conversion: |
842 return self._AddConvertingGetter(attr, html_name, conversion) | 535 return self._AddConvertingGetter(attr, html_name, conversion) |
843 return_type = self._NarrowOutputType(attr.type.id) | 536 return_type = self.SecureOutputType(attr.type.id) |
844 self._members_emitter.Emit( | 537 self._members_emitter.Emit( |
845 # TODO(sra): Use metadata to provide native name. | 538 # TODO(sra): Use metadata to provide native name. |
846 '\n $TYPE get $HTML_NAME => JS("$TYPE", "#.$NAME", this);' | 539 '\n $TYPE get $HTML_NAME => JS("$TYPE", "#.$NAME", this);' |
847 '\n', | 540 '\n', |
848 HTML_NAME=html_name, | 541 HTML_NAME=html_name, |
849 NAME=attr.id, | 542 NAME=attr.id, |
850 TYPE=return_type) | 543 TYPE=return_type) |
851 | 544 |
852 def _AddRenamingSetter(self, attr, html_name): | 545 def _AddRenamingSetter(self, attr, html_name): |
853 self.EmitAttributeDocumentation(attr) | 546 self.EmitAttributeDocumentation(attr) |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
890 '\n', | 583 '\n', |
891 CONVERT=conversion.function_name, | 584 CONVERT=conversion.function_name, |
892 HTML_NAME=html_name, | 585 HTML_NAME=html_name, |
893 NAME=attr.id, | 586 NAME=attr.id, |
894 INPUT_TYPE=conversion.input_type, | 587 INPUT_TYPE=conversion.input_type, |
895 NATIVE_TYPE=conversion.output_type) | 588 NATIVE_TYPE=conversion.output_type) |
896 | 589 |
897 def AmendIndexer(self, element_type): | 590 def AmendIndexer(self, element_type): |
898 pass | 591 pass |
899 | 592 |
900 def AddOperation(self, info, html_name): | 593 def EmitOperation(self, info, html_name): |
901 """ | 594 """ |
902 Arguments: | 595 Arguments: |
903 info: An OperationInfo object. | 596 info: An OperationInfo object. |
904 """ | 597 """ |
905 if self._HasCustomImplementation(info.name): | 598 if self._HasCustomImplementation(info.name): |
906 return | 599 return |
907 | 600 |
908 self.EmitOperationDocumentation(info) | 601 self.EmitOperationDocumentation(info) |
909 | 602 |
910 if IsPureInterface(self._interface.id): | 603 if IsPureInterface(self._interface.id): |
911 self._AddInterfaceOperation(info, html_name) | 604 self._AddInterfaceOperation(info, html_name) |
912 elif any(self._OperationRequiresConversions(op) for op in info.overloads): | 605 elif any(self._OperationRequiresConversions(op) for op in info.overloads): |
913 # Any conversions needed? | 606 # Any conversions needed? |
914 self._AddOperationWithConversions(info, html_name) | 607 self._AddOperationWithConversions(info, html_name) |
915 else: | 608 else: |
916 self._AddDirectNativeOperation(info, html_name) | 609 self._AddDirectNativeOperation(info, html_name) |
917 | 610 |
918 def _AddDirectNativeOperation(self, info, html_name): | 611 def _AddDirectNativeOperation(self, info, html_name): |
919 # Do we need a native body? | 612 # Do we need a native body? |
920 if html_name != info.declared_name: | 613 if html_name != info.declared_name: |
921 return_type = self._NarrowOutputType(info.type_name) | 614 return_type = self.SecureOutputType(info.type_name) |
922 | 615 |
923 operation_emitter = self._members_emitter.Emit('$!SCOPE', | 616 operation_emitter = self._members_emitter.Emit('$!SCOPE', |
924 MODIFIERS='static ' if info.IsStatic() else '', | 617 MODIFIERS='static ' if info.IsStatic() else '', |
925 TYPE=return_type, | 618 TYPE=return_type, |
926 HTML_NAME=html_name, | 619 HTML_NAME=html_name, |
927 NAME=info.declared_name, | 620 NAME=info.declared_name, |
928 PARAMS=info.ParametersDeclaration(self._NarrowInputType)) | 621 PARAMS=info.ParametersDeclaration(self._NarrowInputType)) |
929 | 622 |
930 operation_emitter.Emit( | 623 operation_emitter.Emit( |
931 '\n' | 624 '\n' |
932 #' // @native("$NAME")\n;' | 625 #' // @native("$NAME")\n;' |
933 ' $MODIFIERS$TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n') | 626 ' $MODIFIERS$TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n') |
934 else: | 627 else: |
935 self._members_emitter.Emit( | 628 self._members_emitter.Emit( |
936 '\n' | 629 '\n' |
937 ' $MODIFIERS$TYPE $NAME($PARAMS) native;\n', | 630 ' $MODIFIERS$TYPE $NAME($PARAMS) native;\n', |
938 MODIFIERS='static ' if info.IsStatic() else '', | 631 MODIFIERS='static ' if info.IsStatic() else '', |
939 TYPE=self._NarrowOutputType(info.type_name), | 632 TYPE=self.SecureOutputType(info.type_name), |
940 NAME=info.name, | 633 NAME=info.name, |
941 PARAMS=info.ParametersDeclaration(self._NarrowInputType)) | 634 PARAMS=info.ParametersDeclaration(self._NarrowInputType)) |
942 | 635 |
943 def _AddOperationWithConversions(self, info, html_name): | 636 def _AddOperationWithConversions(self, info, html_name): |
944 # Assert all operations have same return type. | 637 # Assert all operations have same return type. |
945 assert len(set([op.type.id for op in info.operations])) == 1 | 638 assert len(set([op.type.id for op in info.operations])) == 1 |
946 info = info.CopyAndWidenDefaultParameters() | 639 info = info.CopyAndWidenDefaultParameters() |
947 output_conversion = self._OutputConversion(info.type_name, | 640 output_conversion = self._OutputConversion(info.type_name, |
948 info.declared_name) | 641 info.declared_name) |
949 if output_conversion: | 642 if output_conversion: |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1076 if self._IsOptional(operation, argument): | 769 if self._IsOptional(operation, argument): |
1077 check = '?%s' % parameter_names[position] | 770 check = '?%s' % parameter_names[position] |
1078 GenerateCall(operation, position + 1, [check]) | 771 GenerateCall(operation, position + 1, [check]) |
1079 argument_count = position | 772 argument_count = position |
1080 GenerateCall(operation, argument_count, []) | 773 GenerateCall(operation, argument_count, []) |
1081 | 774 |
1082 def _AddInterfaceOperation(self, info, html_name): | 775 def _AddInterfaceOperation(self, info, html_name): |
1083 self._members_emitter.Emit( | 776 self._members_emitter.Emit( |
1084 '\n' | 777 '\n' |
1085 ' $TYPE $NAME($PARAMS);\n', | 778 ' $TYPE $NAME($PARAMS);\n', |
1086 TYPE=self._NarrowOutputType(info.type_name), | 779 TYPE=self.SecureOutputType(info.type_name), |
1087 NAME=info.name, | 780 NAME=info.name, |
1088 PARAMS=info.ParametersDeclaration(self._NarrowInputType)) | 781 PARAMS=info.ParametersDeclaration(self._NarrowInputType)) |
1089 | 782 |
1090 def AddConstant(self, constant): | 783 def AddConstant(self, constant): |
1091 type = TypeOrNothing(self._DartType(constant.type.id), constant.type.id) | 784 type = TypeOrNothing(self._DartType(constant.type.id), constant.type.id) |
1092 self._members_emitter.Emit('\n static const $TYPE$NAME = $VALUE;\n', | 785 self._members_emitter.Emit('\n static const $TYPE$NAME = $VALUE;\n', |
1093 NAME=constant.id, | 786 NAME=constant.id, |
1094 TYPE=type, | 787 TYPE=type, |
1095 VALUE=constant.value) | 788 VALUE=constant.value) |
1096 | 789 |
(...skipping 25 matching lines...) Expand all Loading... |
1122 | 815 |
1123 def CustomJSMembers(self): | 816 def CustomJSMembers(self): |
1124 return _js_custom_members | 817 return _js_custom_members |
1125 | 818 |
1126 def _NarrowToImplementationType(self, type_name): | 819 def _NarrowToImplementationType(self, type_name): |
1127 return self._type_registry.TypeInfo(type_name).narrow_dart_type() | 820 return self._type_registry.TypeInfo(type_name).narrow_dart_type() |
1128 | 821 |
1129 def _NarrowInputType(self, type_name): | 822 def _NarrowInputType(self, type_name): |
1130 return self._NarrowToImplementationType(type_name) | 823 return self._NarrowToImplementationType(type_name) |
1131 | 824 |
1132 def _NarrowOutputType(self, type_name): | |
1133 return SecureOutputType(self, type_name) | |
1134 | |
1135 def _FindShadowedAttribute(self, attr): | 825 def _FindShadowedAttribute(self, attr): |
1136 """Returns (attribute, superinterface) or (None, None).""" | 826 """Returns (attribute, superinterface) or (None, None).""" |
1137 def FindInParent(interface): | 827 def FindInParent(interface): |
1138 """Returns matching attribute in parent, or None.""" | 828 """Returns matching attribute in parent, or None.""" |
1139 if interface.parents: | 829 if interface.parents: |
1140 parent = interface.parents[0] | 830 parent = interface.parents[0] |
1141 if IsDartCollectionType(parent.type.id): | 831 if IsDartCollectionType(parent.type.id): |
1142 return (None, None) | 832 return (None, None) |
1143 if IsPureInterface(parent.type.id): | 833 if IsPureInterface(parent.type.id): |
1144 return (None, None) | 834 return (None, None) |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1196 | 886 |
1197 library_emitter = self._multiemitter.FileEmitter(library_file_path) | 887 library_emitter = self._multiemitter.FileEmitter(library_file_path) |
1198 library_file_dir = os.path.dirname(library_file_path) | 888 library_file_dir = os.path.dirname(library_file_path) |
1199 auxiliary_dir = os.path.relpath(auxiliary_dir, library_file_dir) | 889 auxiliary_dir = os.path.relpath(auxiliary_dir, library_file_dir) |
1200 imports_emitter = library_emitter.Emit( | 890 imports_emitter = library_emitter.Emit( |
1201 self._template, AUXILIARY_DIR=massage_path(auxiliary_dir)) | 891 self._template, AUXILIARY_DIR=massage_path(auxiliary_dir)) |
1202 for path in sorted(self._path_to_emitter.keys()): | 892 for path in sorted(self._path_to_emitter.keys()): |
1203 relpath = os.path.relpath(path, library_file_dir) | 893 relpath = os.path.relpath(path, library_file_dir) |
1204 imports_emitter.Emit( | 894 imports_emitter.Emit( |
1205 "part '$PATH';\n", PATH=massage_path(relpath)) | 895 "part '$PATH';\n", PATH=massage_path(relpath)) |
OLD | NEW |