OLD | NEW |
1 # Copyright (C) 2013 Google Inc. All rights reserved. | 1 # Copyright (C) 2013 Google Inc. All rights reserved. |
| 2 # coding=utf-8 |
2 # | 3 # |
3 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
4 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
5 # met: | 6 # met: |
6 # | 7 # |
7 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
8 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
9 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
10 # copyright notice, this list of conditions and the following disclaimer | 11 # copyright notice, this list of conditions and the following disclaimer |
11 # in the documentation and/or other materials provided with the | 12 # in the documentation and/or other materials provided with the |
(...skipping 13 matching lines...) Expand all Loading... |
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | 29 |
29 """Generate template values for an interface. | 30 """Generate template values for an interface. |
30 | 31 |
31 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler | 32 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler |
32 """ | 33 """ |
33 | 34 |
34 from collections import defaultdict | 35 from collections import defaultdict |
| 36 import itertools |
| 37 from operator import itemgetter |
35 | 38 |
36 import idl_types | 39 import idl_types |
37 from idl_types import IdlType, inherits_interface, IdlArrayOrSequenceType, IdlAr
rayType | 40 from idl_types import IdlType, inherits_interface, IdlArrayOrSequenceType, IdlAr
rayType |
38 import dart_attributes | 41 import dart_attributes |
39 import dart_methods | 42 import dart_methods |
40 import dart_types | 43 import dart_types |
41 from dart_utilities import DartUtilities | 44 from dart_utilities import DartUtilities |
42 from v8_globals import includes | 45 from v8_globals import includes |
| 46 import v8_attributes |
| 47 import v8_interface |
43 | 48 |
44 | 49 |
45 INTERFACE_H_INCLUDES = frozenset([ | 50 INTERFACE_H_INCLUDES = frozenset([ |
46 'bindings/core/dart/DartDOMWrapper.h', | 51 'bindings/core/dart/DartDOMWrapper.h', |
47 'platform/heap/Handle.h', | 52 'platform/heap/Handle.h', |
48 ]) | 53 ]) |
49 | 54 |
50 INTERFACE_CPP_INCLUDES = frozenset([ | 55 INTERFACE_CPP_INCLUDES = frozenset([ |
51 | 56 |
52 'bindings/core/dart/DartUtilities.h', | 57 'bindings/core/dart/DartUtilities.h', |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 for extended_attribute_name in extended_attributes: | 394 for extended_attribute_name in extended_attributes: |
390 ignore_extended_values = IGNORE_EXTENDED_ATTRIBUTES.get(extended_attribu
te_name) | 395 ignore_extended_values = IGNORE_EXTENDED_ATTRIBUTES.get(extended_attribu
te_name) |
391 if ignore_extended_values != None: | 396 if ignore_extended_values != None: |
392 extended_attribute_value = extended_attributes.get(extended_attribut
e_name) | 397 extended_attribute_value = extended_attributes.get(extended_attribut
e_name) |
393 if ((not ignore_extended_values and extended_attribute_value == None
) or | 398 if ((not ignore_extended_values and extended_attribute_value == None
) or |
394 extended_attribute_value in ignore_extended_values): | 399 extended_attribute_value in ignore_extended_values): |
395 return True | 400 return True |
396 return False | 401 return False |
397 | 402 |
398 | 403 |
399 def add_native_entries(interface, constructors, is_custom): | 404 # TODO(terry): Rename genenerate_interface to interface_context. |
400 for constructor in constructors: | 405 def interface_context(interface): |
401 types = None | 406 context = v8_interface.interface_context(interface) |
402 if not is_custom: | |
403 types = [arg['preprocessed_type'] | |
404 for arg in constructor['arguments']] | |
405 argument_names = [arg['name'] for arg in constructor['arguments']] | |
406 native_entry = \ | |
407 DartUtilities.generate_native_entry(interface.name, constructor, | |
408 None, 'Constructor', None, | |
409 argument_names, types) | |
410 constructor.update({'native_entry': native_entry}) | |
411 | 407 |
| 408 includes.clear() |
412 | 409 |
413 def generate_interface(interface): | |
414 includes.clear() | |
415 includes.update(INTERFACE_CPP_INCLUDES) | 410 includes.update(INTERFACE_CPP_INCLUDES) |
416 header_includes = set(INTERFACE_H_INCLUDES) | 411 header_includes = set(INTERFACE_H_INCLUDES) |
417 | 412 |
418 parent_interface = interface.parent | 413 parent_interface = interface.parent |
419 if parent_interface: | 414 if parent_interface: |
420 header_includes.update(dart_types.includes_for_interface(parent_interfac
e)) | 415 header_includes.update(dart_types.includes_for_interface(parent_interfac
e)) |
421 extended_attributes = interface.extended_attributes | 416 extended_attributes = interface.extended_attributes |
422 | 417 |
423 is_audio_buffer = inherits_interface(interface.name, 'AudioBuffer') | |
424 if is_audio_buffer: | |
425 includes.add('modules/webaudio/AudioBuffer.h') | |
426 | |
427 is_document = inherits_interface(interface.name, 'Document') | 418 is_document = inherits_interface(interface.name, 'Document') |
428 if is_document: | 419 if is_document: |
429 # FIXME(vsm): We probably need bindings/dart/DartController and | 420 # FIXME(vsm): We probably need bindings/dart/DartController and |
430 # core/frame/LocalFrame.h here. | 421 # core/frame/LocalFrame.h here. |
431 includes.update(['DartDocument.h']) | 422 includes.update(['DartDocument.h']) |
432 | 423 |
433 if inherits_interface(interface.name, 'DataTransferItemList'): | 424 if inherits_interface(interface.name, 'DataTransferItemList'): |
434 # FIXME(jacobr): this is a hack. | 425 # FIXME(jacobr): this is a hack. |
435 includes.update(['core/html/HTMLCollection.h']) | 426 includes.update(['core/html/HTMLCollection.h']) |
436 | 427 |
437 | 428 |
438 if inherits_interface(interface.name, 'EventTarget'): | 429 if inherits_interface(interface.name, 'EventTarget'): |
439 includes.update(['bindings/core/dart/DartEventListener.h']) | 430 includes.update(['bindings/core/dart/DartEventListener.h']) |
440 | 431 |
441 # [ActiveDOMObject] | |
442 is_active_dom_object = 'ActiveDOMObject' in extended_attributes | |
443 | |
444 # [CheckSecurity] | |
445 is_check_security = 'CheckSecurity' in extended_attributes | |
446 if is_check_security: | |
447 includes.add('bindings/common/BindingSecurity.h') | |
448 | |
449 # [DependentLifetime] | |
450 is_dependent_lifetime = 'DependentLifetime' in extended_attributes | |
451 | |
452 # [MeasureAs] | |
453 # TODO(terry): Remove Me? | |
454 # is_measure_as = 'MeasureAs' in extended_attributes | |
455 # if is_measure_as: | |
456 # includes.add('core/frame/UseCounter.h') | |
457 | |
458 # [SetWrapperReferenceFrom] | |
459 reachable_node_function = extended_attributes.get('SetWrapperReferenceFrom') | |
460 if reachable_node_function: | |
461 # FIXME(vsm): We may need bindings/dart/DartGCController.h instead. | |
462 includes.update(['bindings/core/v8/V8GCController.h', | |
463 'core/dom/Element.h']) | |
464 | |
465 # [SetWrapperReferenceTo] | 432 # [SetWrapperReferenceTo] |
466 set_wrapper_reference_to_list = [{ | 433 set_wrapper_reference_to_list = [{ |
467 'name': argument.name, | 434 'name': argument.name, |
468 # FIXME: properly should be: | 435 # FIXME: properly should be: |
469 # 'cpp_type': argument.idl_type.cpp_type_args(used_as_rvalue_type=True), | 436 # 'cpp_type': argument.idl_type.cpp_type_args(used_as_rvalue_type=True), |
470 # (if type is non-wrapper type like NodeFilter, normally RefPtr) | 437 # (if type is non-wrapper type like NodeFilter, normally RefPtr) |
471 # Raw pointers faster though, and NodeFilter hacky anyway. | 438 # Raw pointers faster though, and NodeFilter hacky anyway. |
472 'cpp_type': argument.idl_type.implemented_as + '*', | 439 'cpp_type': argument.idl_type.implemented_as + '*', |
473 'idl_type': argument.idl_type, | 440 'idl_type': argument.idl_type, |
474 'v8_type': dart_types.v8_type(argument.idl_type.name), | 441 'v8_type': dart_types.v8_type(argument.idl_type.name), |
475 } for argument in extended_attributes.get('SetWrapperReferenceTo', [])] | 442 } for argument in extended_attributes.get('SetWrapperReferenceTo', [])] |
476 for set_wrapper_reference_to in set_wrapper_reference_to_list: | 443 for set_wrapper_reference_to in set_wrapper_reference_to_list: |
477 set_wrapper_reference_to['idl_type'].add_includes_for_type() | 444 set_wrapper_reference_to['idl_type'].add_includes_for_type() |
478 | 445 |
479 # [SpecialWrapFor] | 446 context.update({ |
480 if 'SpecialWrapFor' in extended_attributes: | |
481 special_wrap_for = extended_attributes['SpecialWrapFor'].split('|') | |
482 else: | |
483 special_wrap_for = [] | |
484 for special_wrap_interface in special_wrap_for: | |
485 dart_types.add_includes_for_interface(special_wrap_interface) | |
486 | |
487 # [Custom=Wrap], [SetWrapperReferenceFrom] | |
488 has_visit_dom_wrapper = ( | |
489 DartUtilities.has_extended_attribute_value(interface, 'Custom', 'VisitDO
MWrapper') or | |
490 reachable_node_function or | |
491 set_wrapper_reference_to_list) | |
492 | |
493 this_gc_type = DartUtilities.gc_type(interface) | |
494 | |
495 template_contents = { | |
496 'conditional_string': DartUtilities.conditional_string(interface), # [C
onditional] | 447 'conditional_string': DartUtilities.conditional_string(interface), # [C
onditional] |
497 'cpp_class': DartUtilities.cpp_name(interface), | 448 'cpp_class': DartUtilities.cpp_name(interface), |
498 'gc_type': this_gc_type, | |
499 'has_custom_legacy_call_as_function': DartUtilities.has_extended_attribu
te_value(interface, 'Custom', 'LegacyCallAsFunction'), # [Custom=LegacyCallAsFu
nction] | |
500 'has_custom_to_v8': DartUtilities.has_extended_attribute_value(interface
, 'Custom', 'ToV8'), # [Custom=ToV8] | |
501 'has_custom_wrap': DartUtilities.has_extended_attribute_value(interface,
'Custom', 'Wrap'), # [Custom=Wrap] | |
502 'has_visit_dom_wrapper': has_visit_dom_wrapper, | |
503 'header_includes': header_includes, | 449 'header_includes': header_includes, |
504 'interface_name': interface.name, | 450 'is_garbage_collected': context['gc_type'] == 'GarbageCollectedObject', |
505 'is_active_dom_object': is_active_dom_object, | 451 'is_will_be_garbage_collected': context['gc_type'] == 'WillBeGarbageColl
ectedObject', |
506 'is_audio_buffer': is_audio_buffer, | |
507 'is_check_security': is_check_security, | |
508 'is_dependent_lifetime': is_dependent_lifetime, | |
509 'is_document': is_document, | |
510 'is_event_target': inherits_interface(interface.name, 'EventTarget'), | |
511 'is_exception': interface.is_exception, | |
512 'is_garbage_collected': this_gc_type == 'GarbageCollectedObject', | |
513 'is_will_be_garbage_collected': this_gc_type == 'WillBeGarbageCollectedO
bject', | |
514 'is_node': inherits_interface(interface.name, 'Node'), | |
515 'measure_as': DartUtilities.measure_as(interface), # [MeasureAs] | 452 'measure_as': DartUtilities.measure_as(interface), # [MeasureAs] |
516 'parent_interface': parent_interface, | |
517 'pass_cpp_type': dart_types.cpp_template_type( | 453 'pass_cpp_type': dart_types.cpp_template_type( |
518 dart_types.cpp_ptr_type('PassRefPtr', 'RawPtr', this_gc_type), | 454 dart_types.cpp_ptr_type('PassRefPtr', 'RawPtr', context['gc_type']), |
519 DartUtilities.cpp_name(interface)), | 455 DartUtilities.cpp_name(interface)), |
520 'reachable_node_function': reachable_node_function, | |
521 'runtime_enabled_function': DartUtilities.runtime_enabled_function_name(
interface), # [RuntimeEnabled] | 456 'runtime_enabled_function': DartUtilities.runtime_enabled_function_name(
interface), # [RuntimeEnabled] |
522 'set_wrapper_reference_to_list': set_wrapper_reference_to_list, | 457 'set_wrapper_reference_to_list': set_wrapper_reference_to_list, |
523 'special_wrap_for': special_wrap_for, | |
524 'dart_class': dart_types.dart_type(interface.name), | 458 'dart_class': dart_types.dart_type(interface.name), |
525 'v8_class': DartUtilities.v8_class_name(interface), | 459 'v8_class': DartUtilities.v8_class_name(interface), |
526 'wrapper_configuration': 'WrapperConfiguration::Dependent' | 460 }) |
527 if (has_visit_dom_wrapper or | |
528 is_active_dom_object or | |
529 is_dependent_lifetime) | |
530 else 'WrapperConfiguration::Independent', | |
531 } | |
532 | 461 |
533 # Constructors | 462 # Constructors |
534 constructors = [generate_constructor(interface, constructor) | 463 constructors = [constructor_context(interface, constructor) |
535 for constructor in interface.constructors | 464 for constructor in interface.constructors |
536 # FIXME: shouldn't put named constructors with constructors | 465 # FIXME: shouldn't put named constructors with constructors |
537 # (currently needed for Perl compatibility) | 466 # (currently needed for Perl compatibility) |
538 # Handle named constructors separately | 467 # Handle named constructors separately |
539 if constructor.name == 'Constructor'] | 468 if constructor.name == 'Constructor'] |
540 generate_constructor_overloads(constructors) | 469 if len(constructors) > 1: |
| 470 context.update({'constructor_overloads': overloads_context(constructors)
}) |
541 | 471 |
542 # [CustomConstructor] | 472 # [CustomConstructor] |
543 custom_constructors = [generate_custom_constructor(interface, constructor) | 473 custom_constructors = [custom_constructor_context(interface, constructor) |
544 for constructor in interface.custom_constructors] | 474 for constructor in interface.custom_constructors] |
545 | 475 |
546 # [EventConstructor] | |
547 has_event_constructor = 'EventConstructor' in extended_attributes | |
548 any_type_attributes = [attribute for attribute in interface.attributes | |
549 if attribute.idl_type.name == 'Any'] | |
550 if has_event_constructor: | |
551 includes.add('bindings/core/v8/Dictionary.h') | |
552 if any_type_attributes: | |
553 includes.add('bindings/core/v8/SerializedScriptValue.h') | |
554 | |
555 # [NamedConstructor] | 476 # [NamedConstructor] |
556 named_constructor = generate_named_constructor(interface) | 477 named_constructor = generate_named_constructor(interface) |
557 | 478 |
558 add_native_entries(interface, constructors, bool(custom_constructors)) | 479 generate_method_native_entries(interface, constructors, 'Constructor') |
559 add_native_entries(interface, custom_constructors, bool(custom_constructors)
) | 480 generate_method_native_entries(interface, custom_constructors, 'Constructor'
) |
560 if named_constructor: | 481 if named_constructor: |
561 add_native_entries(interface, [named_constructor], bool(custom_construct
ors)) | 482 generate_method_native_entries(interface, [named_constructor], |
| 483 'Constructor') |
| 484 event_constructor = None |
| 485 if context['has_event_constructor']: |
| 486 event_constructor = { |
| 487 'native_entries': [ |
| 488 DartUtilities.generate_native_entry( |
| 489 interface.name, None, 'Constructor', False, 2)], |
| 490 } |
562 | 491 |
563 if (constructors or custom_constructors or has_event_constructor or | 492 if (context['constructors'] or custom_constructors or context['has_event_con
structor'] or |
564 named_constructor): | 493 named_constructor): |
565 includes.add('core/frame/LocalDOMWindow.h') | 494 includes.add('core/frame/LocalDOMWindow.h') |
566 | 495 |
567 template_contents.update({ | 496 context.update({ |
568 'any_type_attributes': any_type_attributes, | |
569 'constructors': constructors, | 497 'constructors': constructors, |
570 'custom_constructors': custom_constructors, | 498 'custom_constructors': custom_constructors, |
| 499 'event_constructor': event_constructor, |
571 'has_custom_constructor': bool(custom_constructors), | 500 'has_custom_constructor': bool(custom_constructors), |
572 'has_event_constructor': has_event_constructor, | |
573 'interface_length': | 501 'interface_length': |
574 interface_length(interface, constructors + custom_constructors), | 502 v8_interface.interface_length(interface, constructors + custom_const
ructors), |
575 'is_constructor_call_with_document': DartUtilities.has_extended_attribut
e_value( | 503 'is_constructor_call_with_document': DartUtilities.has_extended_attribut
e_value( |
576 interface, 'ConstructorCallWith', 'Document'), # [ConstructorCallWi
th=Document] | 504 interface, 'ConstructorCallWith', 'Document'), # [ConstructorCallWi
th=Document] |
577 'is_constructor_call_with_execution_context': DartUtilities.has_extended
_attribute_value( | 505 'is_constructor_call_with_execution_context': DartUtilities.has_extended
_attribute_value( |
578 interface, 'ConstructorCallWith', 'ExecutionContext'), # [Construct
orCallWith=ExeuctionContext] | 506 interface, 'ConstructorCallWith', 'ExecutionContext'), # [Construct
orCallWith=ExeuctionContext] |
579 'is_constructor_raises_exception': extended_attributes.get('RaisesExcept
ion') == 'Constructor', # [RaisesException=Constructor] | |
580 'named_constructor': named_constructor, | 507 'named_constructor': named_constructor, |
581 }) | 508 }) |
582 | 509 |
583 # Constants | |
584 template_contents.update({ | |
585 'constants': [generate_constant(constant) for constant in interface.cons
tants], | |
586 'do_not_check_constants': 'DoNotCheckConstants' in extended_attributes, | |
587 }) | |
588 | |
589 # Attributes | 510 # Attributes |
590 attributes = [dart_attributes.generate_attribute(interface, attribute) | 511 attributes = [dart_attributes.attribute_context(interface, attribute) |
591 for attribute in interface.attributes | 512 for attribute in interface.attributes |
592 # Skip attributes in the IGNORE_MEMBERS list or if an | 513 # Skip attributes in the IGNORE_MEMBERS list or if an |
593 # extended attribute is in the IGNORE_EXTENDED_ATTRIBUTES. | 514 # extended attribute is in the IGNORE_EXTENDED_ATTRIBUTES. |
594 if (not _suppress_attribute(interface.name, attribute.name
) and | 515 if (not _suppress_attribute(interface.name, attribute.name
) and |
595 not dart_attributes.is_constructor_attribute(attribute
) and | 516 not v8_attributes.is_constructor_attribute(attribute)
and |
596 not _suppress_extended_attributes(attribute.extended_a
ttributes) and | 517 not _suppress_extended_attributes(attribute.extended_a
ttributes) and |
597 not ('DartSuppress' in attribute.extended_attributes a
nd | 518 not ('DartSuppress' in attribute.extended_attributes a
nd |
598 attribute.extended_attributes.get('DartSuppress') ==
None))] | 519 attribute.extended_attributes.get('DartSuppress') ==
None))] |
599 template_contents.update({ | 520 context.update({ |
600 'attributes': attributes, | 521 'attributes': attributes, |
601 'has_accessors': any(attribute['is_expose_js_accessors'] for attribute i
n attributes), | 522 'has_accessors': any(attribute['is_expose_js_accessors'] for attribute i
n attributes), |
602 'has_attribute_configuration': any( | 523 'has_attribute_configuration': any( |
603 not (attribute['is_expose_js_accessors'] or | 524 not (attribute['is_expose_js_accessors'] or |
604 attribute['is_static'] or | 525 attribute['is_static'] or |
605 attribute['runtime_enabled_function'] or | 526 attribute['runtime_enabled_function'] or |
606 attribute['per_context_enabled_function']) | 527 attribute['per_context_enabled_function']) |
607 for attribute in attributes), | 528 for attribute in attributes), |
608 'has_constructor_attributes': any(attribute['constructor_type'] for attr
ibute in attributes), | 529 'has_constructor_attributes': any(attribute['constructor_type'] for attr
ibute in attributes), |
609 'has_per_context_enabled_attributes': any(attribute['per_context_enabled
_function'] for attribute in attributes), | 530 'has_per_context_enabled_attributes': any(attribute['per_context_enabled
_function'] for attribute in attributes), |
610 'has_replaceable_attributes': any(attribute['is_replaceable'] for attrib
ute in attributes), | 531 'has_replaceable_attributes': any(attribute['is_replaceable'] for attrib
ute in attributes), |
611 }) | 532 }) |
612 | 533 |
613 # Methods | 534 # Methods |
614 methods = [dart_methods.generate_method(interface, method) | 535 methods = [dart_methods.method_context(interface, method) |
615 for method in interface.operations | 536 for method in interface.operations |
616 # Skip anonymous special operations (methods name empty). | 537 # Skip anonymous special operations (methods name empty). |
617 # Skip methods in our IGNORE_MEMBERS list. | 538 # Skip methods in our IGNORE_MEMBERS list. |
618 # Skip methods w/ extended attributes in IGNORE_EXTENDED_ATTRIBUT
ES list. | 539 # Skip methods w/ extended attributes in IGNORE_EXTENDED_ATTRIBUT
ES list. |
619 if (method.name and | 540 if (method.name and |
| 541 # detect unnamed getters from v8_interface. |
| 542 method.name != 'anonymousNamedGetter' and |
620 # TODO(terry): Eventual eliminate the IGNORE_MEMBERS in favor
of DartSupress. | 543 # TODO(terry): Eventual eliminate the IGNORE_MEMBERS in favor
of DartSupress. |
621 not _suppress_method(interface.name, method.name) and | 544 not _suppress_method(interface.name, method.name) and |
622 not _suppress_extended_attributes(method.extended_attributes)
and | 545 not _suppress_extended_attributes(method.extended_attributes)
and |
623 not 'DartSuppress' in method.extended_attributes)] | 546 not 'DartSuppress' in method.extended_attributes)] |
624 generate_overloads(methods) | 547 compute_method_overloads_context(methods) |
625 for method in methods: | 548 for method in methods: |
626 method['do_generate_method_configuration'] = ( | 549 method['do_generate_method_configuration'] = ( |
627 method['do_not_check_signature'] and | 550 method['do_not_check_signature'] and |
628 not method['per_context_enabled_function'] and | 551 not method['per_context_enabled_function'] and |
629 # For overloaded methods, only generate one accessor | 552 # For overloaded methods, only generate one accessor |
630 ('overload_index' not in method or method['overload_index'] == 1)) | 553 ('overload_index' not in method or method['overload_index'] == 1)) |
631 | 554 |
632 generate_method_native_entries(interface, methods) | 555 generate_method_native_entries(interface, methods, 'Method') |
633 | 556 |
634 template_contents.update({ | 557 context.update({ |
635 'has_origin_safe_method_setter': any( | 558 'has_origin_safe_method_setter': any( |
636 method['is_check_security_for_frame'] and not method['is_read_only'] | 559 method['is_check_security_for_frame'] and not method['is_read_only'] |
637 for method in methods), | 560 for method in methods), |
638 'has_method_configuration': any(method['do_generate_method_configuration
'] for method in methods), | 561 'has_method_configuration': any(method['do_generate_method_configuration
'] for method in methods), |
639 'has_per_context_enabled_methods': any(method['per_context_enabled_funct
ion'] for method in methods), | 562 'has_per_context_enabled_methods': any(method['per_context_enabled_funct
ion'] for method in methods), |
640 'methods': methods, | 563 'methods': methods, |
641 }) | 564 }) |
642 | 565 |
643 native_entries = generate_native_entries(interface, constructors, | 566 context.update({ |
644 custom_constructors, attributes, | |
645 methods, named_constructor) | |
646 | |
647 template_contents.update({ | |
648 'indexed_property_getter': indexed_property_getter(interface), | 567 'indexed_property_getter': indexed_property_getter(interface), |
649 'indexed_property_setter': indexed_property_setter(interface), | 568 'indexed_property_setter': indexed_property_setter(interface), |
650 'indexed_property_deleter': indexed_property_deleter(interface), | 569 'indexed_property_deleter': v8_interface.indexed_property_deleter(interf
ace), |
651 'is_override_builtins': 'OverrideBuiltins' in extended_attributes, | 570 'is_override_builtins': 'OverrideBuiltins' in extended_attributes, |
652 'named_property_getter': named_property_getter(interface), | 571 'named_property_getter': named_property_getter(interface), |
653 'named_property_setter': named_property_setter(interface), | 572 'named_property_setter': named_property_setter(interface), |
654 'named_property_deleter': named_property_deleter(interface), | 573 'named_property_deleter': v8_interface.named_property_deleter(interface)
, |
| 574 }) |
| 575 |
| 576 generate_native_entries_for_specials(interface, context) |
| 577 |
| 578 native_entries = generate_interface_native_entries(context) |
| 579 |
| 580 context.update({ |
655 'native_entries': native_entries, | 581 'native_entries': native_entries, |
656 }) | 582 }) |
657 | 583 |
658 return template_contents | 584 return context |
659 | 585 |
660 | 586 |
661 def generate_native_entries(interface, constructors, custom_constructors, | 587 def generate_interface_native_entries(context): |
662 attributes, methods, named_constructor): | 588 entries = {} |
663 entries = [] | 589 |
664 for constructor in constructors: | 590 def add(ne): |
665 entries.append(constructor['native_entry']) | 591 entries[ne['blink_entry']] = ne |
666 for constructor in custom_constructors: | 592 |
667 entries.append(constructor['native_entry']) | 593 def addAll(nes): |
668 if named_constructor: | 594 for ne in nes: |
669 entries.append(named_constructor['native_entry']) | 595 add(ne) |
| 596 |
| 597 for constructor in context['constructors']: |
| 598 addAll(constructor['native_entries']) |
| 599 for constructor in context['custom_constructors']: |
| 600 addAll(constructor['native_entries']) |
| 601 if context['named_constructor']: |
| 602 addAll(context['named_constructor']['native_entries']) |
| 603 if context['event_constructor']: |
| 604 addAll(context['event_constructor']['native_entries']) |
| 605 for method in context['methods']: |
| 606 addAll(method['native_entries']) |
| 607 for attribute in context['attributes']: |
| 608 add(attribute['native_entry_getter']) |
| 609 if not attribute['is_read_only'] or attribute['put_forwards']: |
| 610 add(attribute['native_entry_setter']) |
| 611 if context['indexed_property_getter']: |
| 612 addAll(context['indexed_property_getter']['native_entries']) |
| 613 if context['indexed_property_setter']: |
| 614 addAll(context['indexed_property_setter']['native_entries']) |
| 615 if context['indexed_property_deleter']: |
| 616 addAll(context['indexed_property_deleter']['native_entries']) |
| 617 if context['named_property_getter']: |
| 618 addAll(context['named_property_getter']['native_entries']) |
| 619 if context['named_property_setter']: |
| 620 addAll(context['named_property_setter']['native_entries']) |
| 621 if context['named_property_deleter']: |
| 622 addAll(context['named_property_deleter']['native_entries']) |
| 623 return list(entries.values()) |
| 624 |
| 625 |
| 626 def generate_method_native_entry(interface, method, count, kind): |
| 627 name = method.get('name') |
| 628 is_static = bool(method.get('is_static')) |
| 629 native_entry = \ |
| 630 DartUtilities.generate_native_entry(interface.name, name, |
| 631 kind, is_static, count) |
| 632 return native_entry |
| 633 |
| 634 |
| 635 def generate_method_native_entries(interface, methods, kind): |
670 for method in methods: | 636 for method in methods: |
671 entries.extend(method['native_entries']) | 637 native_entries = [] |
672 for attribute in attributes: | 638 arg_count = method['number_of_arguments'] |
673 entries.append(attribute['native_entry_getter']) | 639 min_arg_count = method['number_of_required_arguments'] |
674 entries.append(attribute['native_entry_setter']) | 640 lb = min_arg_count - 2 if min_arg_count > 2 else 0 |
675 return entries | 641 for x in range(lb, arg_count + 3): |
676 | 642 native_entry = \ |
677 | 643 generate_method_native_entry(interface, method, x, kind) |
678 # [DeprecateAs], [Reflect], [RuntimeEnabled] | 644 native_entries.append(native_entry) |
679 def generate_constant(constant): | 645 |
680 # (Blink-only) string literals are unquoted in tokenizer, must be re-quoted | 646 method.update({'native_entries': native_entries}) |
681 # in C++. | |
682 if constant.idl_type.name == 'String': | |
683 value = '"%s"' % constant.value | |
684 else: | |
685 value = constant.value | |
686 | |
687 extended_attributes = constant.extended_attributes | |
688 return { | |
689 'cpp_class': extended_attributes.get('PartialInterfaceImplementedAs'), | |
690 'name': constant.name, | |
691 # FIXME: use 'reflected_name' as correct 'name' | |
692 'reflected_name': extended_attributes.get('Reflect', constant.name), | |
693 'runtime_enabled_function': DartUtilities.runtime_enabled_function_name(
constant), | |
694 'value': value, | |
695 } | |
696 | 647 |
697 | 648 |
698 ################################################################################ | 649 ################################################################################ |
699 # Overloads | 650 # Overloads |
700 ################################################################################ | 651 ################################################################################ |
701 | 652 |
702 def generate_method_native_entry(interface, method, count, optional_index): | 653 def compute_method_overloads_context(methods): |
703 types = None | 654 # Regular methods |
704 if not method['is_custom']: | 655 compute_method_overloads_context_by_type([method for method in methods |
705 types = [arg['preprocessed_type'] for arg in method['arguments'][0:count
]] | 656 if not method['is_static']]) |
706 if method['is_call_with_script_arguments']: | 657 # Static methods |
707 types.append("object") | 658 compute_method_overloads_context_by_type([method for method in methods |
708 argument_names = [arg['name'] for arg in method['arguments'][0:count]] | 659 if method['is_static']]) |
709 name = method['name'] | 660 |
710 native_entry = \ | 661 |
711 DartUtilities.generate_native_entry(interface.name, method, | 662 def compute_method_overloads_context_by_type(methods): |
712 name, 'Method', | 663 """Computes |method.overload*| template values. |
713 optional_index, | 664 |
714 argument_names, types) | 665 Called separately for static and non-static (regular) methods, |
715 return native_entry | 666 as these are overloaded separately. |
716 | 667 Modifies |method| in place for |method| in |methods|. |
717 | 668 Doesn't change the |methods| list itself (only the values, i.e. individual |
718 def generate_method_native_entries(interface, methods): | 669 methods), so ok to treat these separately. |
719 for method in methods: | 670 """ |
720 native_entries = [] | |
721 required_arg_count = method['number_of_required_arguments'] | |
722 arg_count = method['number_of_arguments'] | |
723 if required_arg_count != arg_count: | |
724 for x in range(required_arg_count, arg_count + 1): | |
725 # This is really silly, but is here for now just to match up | |
726 # the existing name generation in the old dart:html scripts | |
727 index = arg_count - x + 1 | |
728 native_entry = \ | |
729 generate_method_native_entry(interface, method, x, index) | |
730 native_entries.append(native_entry) | |
731 else: | |
732 # Eventually, we should probably always generate an unindexed | |
733 # native entry, to handle cases like | |
734 # addEventListener in which we suppress the optionality, | |
735 # and in general to make us more robust against optional changes | |
736 native_entry = \ | |
737 generate_method_native_entry(interface, method, arg_count, None) | |
738 native_entries.append(native_entry) | |
739 | |
740 method.update({'native_entries': native_entries}) | |
741 | |
742 def generate_overloads(methods): | |
743 generate_overloads_by_type(methods, is_static=False) # Regular methods | |
744 generate_overloads_by_type(methods, is_static=True) | |
745 | |
746 | |
747 def generate_overloads_by_type(methods, is_static): | |
748 # Generates |overloads| template values and modifies |methods| in place; | |
749 # |is_static| flag used (instead of partitioning list in 2) because need to | |
750 # iterate over original list of methods to modify in place | |
751 method_counts = defaultdict(lambda: 0) | |
752 for method in methods: | |
753 if method['is_static'] != is_static: | |
754 continue | |
755 name = method['name'] | |
756 # FIXME(vsm): We don't seem to capture optional param | |
757 # overloads here. | |
758 method_counts[name] += 1 | |
759 | |
760 # Filter to only methods that are actually overloaded | |
761 overloaded_method_counts = dict((name, count) | |
762 for name, count in method_counts.iteritems() | |
763 if count > 1) | |
764 | |
765 # Add overload information only to overloaded methods, so template code can | 671 # Add overload information only to overloaded methods, so template code can |
766 # easily verify if a function is overloaded | 672 # easily verify if a function is overloaded |
767 method_overloads = defaultdict(list) | 673 for name, overloads in v8_interface.method_overloads_by_name(methods): |
768 for method in methods: | 674 # Resolution function is generated after last overloaded function; |
769 name = method['name'] | 675 # package necessary information into |method.overloads| for that method. |
770 if (method['is_static'] != is_static or | 676 overloads[-1]['overloads'] = overloads_context(overloads) |
771 name not in overloaded_method_counts): | 677 overloads[-1]['overloads']['name'] = name |
772 continue | 678 |
773 # Overload index includes self, so first append, then compute index | 679 |
774 method_overloads[name].append(method) | 680 def overloads_context(overloads): |
775 method.update({ | 681 """Returns |overloads| template values for a single name. |
776 'overload_index': len(method_overloads[name]), | 682 |
777 'overload_resolution_expression': overload_resolution_expression(met
hod), | 683 Sets |method.overload_index| in place for |method| in |overloads| |
778 }) | 684 and returns dict of overall overload template values. |
779 # FIXME(vsm): Looks like we only handle optional parameters if | 685 """ |
780 # the method is already overloaded. For a non-overloaded method | 686 assert len(overloads) > 1 # only apply to overloaded names |
781 # with optional parameters, we never get here. | 687 for index, method in enumerate(overloads, 1): |
782 | 688 method['overload_index'] = index |
783 # Resolution function is generated after last overloaded function; | 689 |
784 # package necessary information into |method.overloads| for that method. | 690 effective_overloads_by_length = v8_interface.effective_overload_set_by_lengt
h(overloads) |
785 for method in methods: | 691 lengths = [length for length, _ in effective_overloads_by_length] |
786 if (method['is_static'] != is_static or | 692 name = overloads[0].get('name', '<constructor>') |
787 'overload_index' not in method): | 693 |
788 continue | 694 # Check and fail if all overloads with the shortest acceptable arguments |
789 name = method['name'] | 695 # list are runtime enabled, since we would otherwise set 'length' on the |
790 if method['overload_index'] != overloaded_method_counts[name]: | 696 # function object to an incorrect value when none of those overloads were |
791 continue | 697 # actually enabled at runtime. The exception is if all overloads are |
792 overloads = method_overloads[name] | 698 # controlled by the same runtime enabled feature, in which case there would |
793 minimum_number_of_required_arguments = min( | 699 # be no function object at all if it is not enabled. |
794 overload['number_of_required_arguments'] | 700 shortest_overloads = effective_overloads_by_length[0][1] |
795 for overload in overloads) | 701 if (all(method.get('runtime_enabled_function') |
796 method['overloads'] = { | 702 for method, _, _ in shortest_overloads) and |
797 'has_exception_state': bool(minimum_number_of_required_arguments), | 703 not v8_interface.common_value(overloads, 'runtime_enabled_function')): |
798 'methods': overloads, | 704 raise ValueError('Function.length of %s depends on runtime enabled featu
res' % name) |
799 'minimum_number_of_required_arguments': minimum_number_of_required_a
rguments, | 705 |
800 'name': name, | 706 return { |
801 } | 707 'deprecate_all_as': v8_interface.common_value(overloads, 'deprecate_as')
, # [DeprecateAs] |
802 | 708 'exposed_test_all': v8_interface.common_value(overloads, 'exposed_test')
, # [Exposed] |
803 | 709 'length_tests_methods': length_tests_methods(effective_overloads_by_leng
th), |
804 def overload_resolution_expression(method): | 710 # 1. Let maxarg be the length of the longest type list of the |
805 # Expression is an OR of ANDs: each term in the OR corresponds to a | 711 # entries in S. |
806 # possible argument count for a given method, with type checks. | 712 'maxarg': lengths[-1], |
807 # FIXME: Blink's overload resolution algorithm is incorrect, per: | 713 'measure_all_as': v8_interface.common_value(overloads, 'measure_as'), #
[MeasureAs] |
808 # Implement WebIDL overload resolution algorithm. | 714 'minarg': lengths[0], |
809 # https://code.google.com/p/chromium/issues/detail?id=293561 | 715 'per_context_enabled_function_all': v8_interface.common_value(overloads,
'per_context_enabled_function'), # [PerContextEnabled] |
| 716 'runtime_enabled_function_all': v8_interface.common_value(overloads, 'ru
ntime_enabled_function'), # [RuntimeEnabled] |
| 717 'valid_arities': lengths |
| 718 # Only need to report valid arities if there is a gap in the |
| 719 # sequence of possible lengths, otherwise invalid length means |
| 720 # "not enough arguments". |
| 721 if lengths[-1] - lengths[0] != len(lengths) - 1 else None, |
| 722 } |
| 723 |
| 724 |
| 725 def length_tests_methods(effective_overloads_by_length): |
| 726 """Returns sorted list of resolution tests and associated methods, by length
. |
| 727 |
| 728 This builds the main data structure for the overload resolution loop. |
| 729 For a given argument length, bindings test argument at distinguishing |
| 730 argument index, in order given by spec: if it is compatible with |
| 731 (optionality or) type required by an overloaded method, resolve to that |
| 732 method. |
| 733 |
| 734 Returns: |
| 735 [(length, [(test, method)])] |
| 736 """ |
| 737 return [(length, list(resolution_tests_methods(effective_overloads))) |
| 738 for length, effective_overloads in effective_overloads_by_length] |
| 739 |
| 740 |
| 741 DART_CHECK_TYPE = { |
| 742 'ArrayBufferView': 'Dart_IsTypedData({cpp_value})', |
| 743 'ArrayBuffer': 'Dart_IsByteBuffer({cpp_value})', |
| 744 'Uint8Array': 'DartUtilities::isUint8Array({cpp_value})', |
| 745 'Uint8ClampedArray': 'DartUtilities::isUint8ClampedArray({cpp_value})', |
| 746 } |
| 747 |
| 748 |
| 749 def resolution_tests_methods(effective_overloads): |
| 750 """Yields resolution test and associated method, in resolution order, for ef
fective overloads of a given length. |
| 751 |
| 752 This is the heart of the resolution algorithm. |
| 753 http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm |
| 754 |
| 755 Note that a given method can be listed multiple times, with different tests! |
| 756 This is to handle implicit type conversion. |
| 757 |
| 758 Returns: |
| 759 [(test, method)] |
| 760 """ |
| 761 methods = [effective_overload[0] |
| 762 for effective_overload in effective_overloads] |
| 763 if len(methods) == 1: |
| 764 # If only one method with a given length, no test needed |
| 765 yield 'true', methods[0] |
| 766 return |
| 767 |
| 768 # 6. If there is more than one entry in S, then set d to be the |
| 769 # distinguishing argument index for the entries of S. |
| 770 index = v8_interface.distinguishing_argument_index(effective_overloads) |
| 771 # (7-9 are for handling |undefined| values for optional arguments before |
| 772 # the distinguishing argument (as "missing"), so you can specify only some |
| 773 # optional arguments. We don't support this, so we skip these steps.) |
| 774 # 10. If i = d, then: |
| 775 # (d is the distinguishing argument index) |
| 776 # 1. Let V be argi. |
| 777 # Note: This is the argument that will be used to resolve which |
| 778 # overload is selected. |
| 779 cpp_value = 'Dart_GetNativeArgument(args, %s + argOffset)' % index |
| 780 |
| 781 # Extract argument and IDL type to simplify accessing these in each loop. |
| 782 arguments = [method['arguments'][index] for method in methods] |
| 783 arguments_methods = zip(arguments, methods) |
| 784 idl_types = [argument['idl_type_object'] for argument in arguments] |
| 785 idl_types_methods = zip(idl_types, methods) |
| 786 |
| 787 # We can't do a single loop through all methods or simply sort them, because |
| 788 # a method may be listed in multiple steps of the resolution algorithm, and |
| 789 # which test to apply differs depending on the step. |
810 # | 790 # |
811 # Currently if distinguishing non-primitive type from primitive type, | 791 # Instead, we need to go through all methods at each step, either finding |
812 # (e.g., sequence<DOMString> from DOMString or Dictionary from double) | 792 # first match (if only one test is allowed) or filtering to matches (if |
813 # the method with a non-primitive type argument must appear *first* in the | 793 # multiple tests are allowed), and generating an appropriate tests. |
814 # IDL file, since we're not adding a check to primitive types. | 794 |
815 # FIXME: Once fixed, check IDLs, as usually want methods with primitive | 795 # 2. If V is undefined, and there is an entry in S whose list of |
816 # types to appear first (style-wise). | 796 # optionality values has "optional" at index i, then remove from S all |
817 # | 797 # other entries. |
818 # Properly: | 798 try: |
819 # 1. Compute effective overload set. | 799 method = next(method for argument, method in arguments_methods |
820 # 2. First check type list length. | 800 if argument['is_optional']) |
821 # 3. If multiple entries for given length, compute distinguishing argument | 801 test = 'Dart_IsNull(%s)' % cpp_value |
822 # index and have check for that type. | 802 yield test, method |
823 arguments = method['arguments'] | 803 except StopIteration: |
824 overload_checks = [overload_check_expression(method, index) | 804 pass |
825 # check *omitting* optional arguments at |index| and up: | 805 |
826 # index 0 => argument_count 0 (no arguments) | 806 # 3. Otherwise: if V is null or undefined, and there is an entry in S that |
827 # index 1 => argument_count 1 (index 0 argument only) | 807 # has one of the following types at position i of its type list, |
828 for index, argument in enumerate(arguments) | 808 # - a nullable type |
829 if argument['is_optional']] | 809 try: |
830 # FIXME: this is wrong if a method has optional arguments and a variadic | 810 method = next(method for idl_type, method in idl_types_methods |
831 # one, though there are not yet any examples of this | 811 if idl_type.is_nullable) |
832 if not method['is_variadic']: | 812 test = 'Dart_IsNull(%s)' % cpp_value |
833 # Includes all optional arguments (len = last index + 1) | 813 yield test, method |
834 overload_checks.append(overload_check_expression(method, len(arguments))
) | 814 except StopIteration: |
835 return ' || '.join('(%s)' % check for check in overload_checks) | 815 pass |
836 | 816 |
837 | 817 # 4. Otherwise: if V is a platform object - but not a platform array |
838 def overload_check_expression(method, argument_count): | 818 # object - and there is an entry in S that has one of the following |
839 overload_checks = ['info.Length() == %s' % argument_count] | 819 # types at position i of its type list, |
840 arguments = method['arguments'][:argument_count] | 820 # - an interface type that V implements |
841 overload_checks.extend(overload_check_argument(index, argument) | 821 # (Unlike most of these tests, this can return multiple methods, since we |
842 for index, argument in | 822 # test if it implements an interface. Thus we need a for loop, not a next.) |
843 enumerate(arguments)) | 823 # (We distinguish wrapper types from built-in interface types.) |
844 return ' && '.join('(%s)' % check for check in overload_checks if check) | 824 for idl_type, method in ((idl_type, method) |
845 | 825 for idl_type, method in idl_types_methods |
846 | 826 if idl_type.is_wrapper_type): |
847 def overload_check_argument(index, argument): | 827 fmtstr = 'Dart{idl_type}::hasInstance({cpp_value})' |
848 def null_or_optional_check(): | 828 if idl_type.base_type in DART_CHECK_TYPE: |
849 # If undefined is passed for an optional argument, the argument should | 829 fmtstr = DART_CHECK_TYPE[idl_type.base_type] |
850 # be treated as missing; otherwise undefined is not allowed. | 830 test = fmtstr.format(idl_type=idl_type.base_type, cpp_value=cpp_value) |
851 | 831 yield test, method |
852 # FIXME(vsm): We need Dart specific checks here. | 832 |
853 if idl_type.is_nullable: | 833 # 8. Otherwise: if V is any kind of object except for a native Date object, |
854 if argument['is_optional']: | 834 # a native RegExp object, and there is an entry in S that has one of the |
855 return 'isUndefinedOrNull(%s)' | 835 # following types at position i of its type list, |
856 return '%s->IsNull()' | 836 # - an array type |
857 if argument['is_optional']: | 837 # - a sequence type |
858 return '%s->IsUndefined()' | 838 # ... |
859 return None | 839 # - a dictionary |
860 | 840 try: |
861 cpp_value = 'info[%s]' % index | 841 # FIXME: IDL dictionary not implemented, so use Blink Dictionary |
862 idl_type = argument['idl_type_object'] | 842 # http://crbug.com/321462 |
863 # FIXME(vsm): We need Dart specific checks for the rest of this method. | 843 idl_type, method = next((idl_type, method) |
864 # FIXME: proper type checking, sharing code with attributes and methods | 844 for idl_type, method in idl_types_methods |
865 # FIXME(terry): DartStrictTypeChecking no longer supported; TypeChecking is | 845 if (idl_type.native_array_element_type or |
866 # new extended attribute. | 846 idl_type.name == 'Dictionary')) |
867 if idl_type.name == 'String' and argument['is_strict_type_checking']: | 847 if idl_type.native_array_element_type: |
868 return ' || '.join(['isUndefinedOrNull(%s)' % cpp_value, | 848 # (We test for Array instead of generic Object to type-check.) |
869 '%s->IsString()' % cpp_value, | 849 # FIXME: test for Object during resolution, then have type check for |
870 '%s->IsObject()' % cpp_value]) | 850 # Array in overloaded method: http://crbug.com/262383 |
871 if idl_type.native_array_element_type: | 851 test = 'Dart_IsList(%s)' % cpp_value |
872 return '%s->IsArray()' % cpp_value | 852 else: |
873 if idl_type.is_callback_interface: | 853 # FIXME: should be '{1}->IsObject() && !{1}->IsDate() && !{1}->IsReg
Exp()'.format(cpp_value) |
874 return ' || '.join(['%s->IsNull()' % cpp_value, | 854 # FIXME: the IsDate and IsRegExp checks can be skipped if we've |
875 '%s->IsFunction()' % cpp_value]) | 855 # already generated tests for them. |
876 if idl_type.is_wrapper_type: | 856 test = 'Dart_IsInstance(%s)' % cpp_value |
877 type_check = 'V8{idl_type}::hasInstance({cpp_value}, info.GetIsolate())'
.format(idl_type=idl_type.base_type, cpp_value=cpp_value) | 857 yield test, method |
878 if idl_type.is_nullable: | 858 except StopIteration: |
879 type_check = ' || '.join(['%s->IsNull()' % cpp_value, type_check]) | 859 pass |
880 return type_check | 860 |
881 if idl_type.is_interface_type: | 861 # (Check for exact type matches before performing automatic type conversion; |
882 # Non-wrapper types are just objects: we don't distinguish type | 862 # only needed if distinguishing between primitive types.) |
883 # We only allow undefined for non-wrapper types (notably Dictionary), | 863 if len([idl_type.is_primitive_type for idl_type in idl_types]) > 1: |
884 # as we need it for optional Dictionary arguments, but we don't want to | 864 # (Only needed if match in step 11, otherwise redundant.) |
885 # change behavior of existing bindings for other types. | 865 if any(idl_type.is_string_type or idl_type.is_enum |
886 type_check = '%s->IsObject()' % cpp_value | 866 for idl_type in idl_types): |
887 added_check_template = null_or_optional_check() | 867 # 10. Otherwise: if V is a Number value, and there is an entry in S |
888 if added_check_template: | 868 # that has one of the following types at position i of its type |
889 type_check = ' || '.join([added_check_template % cpp_value, | 869 # list, |
890 type_check]) | 870 # - a numeric type |
891 return type_check | 871 try: |
892 return None | 872 method = next(method for idl_type, method in idl_types_methods |
| 873 if idl_type.is_numeric_type) |
| 874 test = 'Dart_IsNumber(%s)' % cpp_value |
| 875 yield test, method |
| 876 except StopIteration: |
| 877 pass |
| 878 |
| 879 # (Perform automatic type conversion, in order. If any of these match, |
| 880 # that's the end, and no other tests are needed.) To keep this code simple, |
| 881 # we rely on the C++ compiler's dead code elimination to deal with the |
| 882 # redundancy if both cases below trigger. |
| 883 |
| 884 # 11. Otherwise: if there is an entry in S that has one of the following |
| 885 # types at position i of its type list, |
| 886 # - DOMString |
| 887 # - ByteString |
| 888 # - ScalarValueString [a DOMString typedef, per definition.] |
| 889 # - an enumeration type |
| 890 try: |
| 891 method = next(method for idl_type, method in idl_types_methods |
| 892 if idl_type.is_string_type or idl_type.is_enum) |
| 893 yield 'true', method |
| 894 except StopIteration: |
| 895 pass |
| 896 |
| 897 # 12. Otherwise: if there is an entry in S that has one of the following |
| 898 # types at position i of its type list, |
| 899 # - a numeric type |
| 900 try: |
| 901 method = next(method for idl_type, method in idl_types_methods |
| 902 if idl_type.is_numeric_type) |
| 903 yield 'true', method |
| 904 except StopIteration: |
| 905 pass |
893 | 906 |
894 | 907 |
895 ################################################################################ | 908 ################################################################################ |
896 # Constructors | 909 # Constructors |
897 ################################################################################ | 910 ################################################################################ |
898 | 911 |
899 # [Constructor] | 912 # [Constructor] |
900 def generate_custom_constructor(interface, constructor): | 913 def custom_constructor_context(interface, constructor): |
901 return { | 914 return { |
902 'arguments': [custom_constructor_argument(argument, index) | 915 'arguments': [custom_constructor_argument(argument, index) |
903 for index, argument in enumerate(constructor.arguments)], | 916 for index, argument in enumerate(constructor.arguments)], |
904 'auto_scope': 'true', | 917 'auto_scope': 'true', |
905 'is_auto_scope': True, | 918 'is_auto_scope': True, |
| 919 'is_call_with_script_arguments': False, |
| 920 'is_custom': True, |
906 'number_of_arguments': len(constructor.arguments), | 921 'number_of_arguments': len(constructor.arguments), |
907 'number_of_required_arguments': | 922 'number_of_required_arguments': |
908 number_of_required_arguments(constructor), | 923 v8_interface.number_of_required_arguments(constructor), |
909 } | 924 } |
910 | 925 |
911 | 926 |
912 # We don't need much from this - just the idl_type_objects and preproceed_type | 927 # We don't need much from this - just the idl_type_objects and preproceed_type |
913 # to use in generating the resolver strings. | 928 # to use in generating the resolver strings. |
914 def custom_constructor_argument(argument, index): | 929 def custom_constructor_argument(argument, index): |
915 return { | 930 return { |
916 'idl_type_object': argument.idl_type, | 931 'idl_type_object': argument.idl_type, |
917 'name': argument.name, | 932 'name': argument.name, |
918 'preprocessed_type': str(argument.idl_type.preprocessed_type), | 933 'preprocessed_type': str(argument.idl_type.preprocessed_type), |
919 } | 934 } |
920 | 935 |
921 | 936 |
922 # [Constructor] | 937 # [Constructor] |
923 def generate_constructor(interface, constructor): | 938 def constructor_context(interface, constructor): |
924 return { | 939 return { |
925 'argument_list': constructor_argument_list(interface, constructor), | 940 'arguments': [dart_methods.argument_context(interface, constructor, argu
ment, index) |
926 # TODO(terry): Use dart_methods.generate_argument instead constructor_ar
gument. | |
927 'arguments': [constructor_argument(interface, argument, index) | |
928 for index, argument in enumerate(constructor.arguments)], | 941 for index, argument in enumerate(constructor.arguments)], |
| 942 'auto_scope': 'true', |
| 943 'cpp_value': dart_methods.cpp_value( |
| 944 interface, constructor, len(constructor.arguments)), |
929 'has_exception_state': | 945 'has_exception_state': |
930 # [RaisesException=Constructor] | 946 # [RaisesException=Constructor] |
931 interface.extended_attributes.get('RaisesException') == 'Constructor
' or | 947 interface.extended_attributes.get('RaisesException') == 'Constructor
' or |
932 any(argument for argument in constructor.arguments | 948 any(argument for argument in constructor.arguments |
933 if argument.idl_type.name == 'SerializedScriptValue' or | 949 if argument.idl_type.name == 'SerializedScriptValue' or |
934 argument.idl_type.is_integer_type), | 950 argument.idl_type.is_integer_type), |
| 951 'is_auto_scope': True, |
| 952 'is_call_with_script_arguments': False, |
935 'is_constructor': True, | 953 'is_constructor': True, |
936 'auto_scope': 'true', | 954 'is_custom': False, |
937 'is_auto_scope': True, | |
938 'is_variadic': False, # Required for overload resolution | 955 'is_variadic': False, # Required for overload resolution |
939 'number_of_required_arguments': | 956 'number_of_required_arguments': |
940 number_of_required_arguments(constructor), | 957 v8_interface.number_of_required_arguments(constructor), |
941 'number_of_arguments': len(constructor.arguments), | 958 'number_of_arguments': len(constructor.arguments), |
942 } | 959 } |
943 | 960 |
944 | 961 |
945 def constructor_argument_list(interface, constructor): | |
946 # FIXME: unify with dart_methods.cpp_argument. | |
947 | |
948 def cpp_argument(argument): | |
949 argument_name = dart_types.check_reserved_name(argument.name) | |
950 idl_type = argument.idl_type | |
951 # FIXMEDART: there has to be a cleaner way to check for arraylike | |
952 # types such as Uint8ClampedArray. | |
953 if isinstance(idl_type, IdlArrayType) or idl_type.preprocessed_type.is_t
yped_array_type: | |
954 return '%s.get()' % argument_name | |
955 | |
956 return argument_name | |
957 | |
958 arguments = [] | |
959 # [ConstructorCallWith=ExecutionContext] | |
960 if DartUtilities.has_extended_attribute_value(interface, 'ConstructorCallWit
h', 'ExecutionContext'): | |
961 arguments.append('context') | |
962 # [ConstructorCallWith=Document] | |
963 if DartUtilities.has_extended_attribute_value(interface, 'ConstructorCallWit
h', 'Document'): | |
964 arguments.append('document') | |
965 | |
966 arguments.extend([cpp_argument(argument) for argument in constructor.argumen
ts]) | |
967 | |
968 # [RaisesException=Constructor] | |
969 if interface.extended_attributes.get('RaisesException') == 'Constructor': | |
970 arguments.append('es') | |
971 | |
972 return arguments | |
973 | |
974 | |
975 # TODO(terry): Eliminate this function use dart_methods.generate_argument instea
d | |
976 # for all constructor arguments. | |
977 def constructor_argument(interface, argument, index): | |
978 idl_type = argument.idl_type | |
979 default_value = str(argument.default_value) if argument.default_value else N
one | |
980 | |
981 argument_content = { | |
982 'cpp_type': idl_type.cpp_type_args(), | |
983 'local_cpp_type': idl_type.cpp_type_args(argument.extended_attributes, r
aw_type=True), | |
984 # FIXME: check that the default value's type is compatible with the argu
ment's | |
985 'default_value': default_value, | |
986 # FIXME: remove once [Default] removed and just use argument.default_val
ue | |
987 'has_default': 'Default' in argument.extended_attributes or default_valu
e, | |
988 'idl_type_object': idl_type, | |
989 'preprocessed_type': str(idl_type.preprocessed_type), | |
990 # Dictionary is special-cased, but arrays and sequences shouldn't be | |
991 'idl_type': idl_type.native_array_element_type, | |
992 'index': index, | |
993 'is_array_or_sequence_type': not not idl_type.native_array_element_type, | |
994 'is_optional': argument.is_optional, | |
995 'is_strict_type_checking': False, # Required for overload resolution | |
996 'name': argument.name, | |
997 'dart_value_to_local_cpp_value': dart_methods.dart_value_to_local_cpp_va
lue(interface, argument, index), | |
998 } | |
999 return argument_content | |
1000 | |
1001 | |
1002 def generate_constructor_overloads(constructors): | |
1003 if len(constructors) <= 1: | |
1004 return | |
1005 for overload_index, constructor in enumerate(constructors): | |
1006 constructor.update({ | |
1007 'overload_index': overload_index + 1, | |
1008 'overload_resolution_expression': | |
1009 overload_resolution_expression(constructor), | |
1010 }) | |
1011 | |
1012 | |
1013 # [NamedConstructor] | 962 # [NamedConstructor] |
1014 def generate_named_constructor(interface): | 963 def generate_named_constructor(interface): |
1015 extended_attributes = interface.extended_attributes | 964 extended_attributes = interface.extended_attributes |
1016 if 'NamedConstructor' not in extended_attributes: | 965 if 'NamedConstructor' not in extended_attributes: |
1017 return None | 966 return None |
1018 # FIXME: parser should return named constructor separately; | 967 # FIXME: parser should return named constructor separately; |
1019 # included in constructors (and only name stored in extended attribute) | 968 # included in constructors (and only name stored in extended attribute) |
1020 # for Perl compatibility | 969 # for Perl compatibility |
1021 idl_constructor = interface.constructors[0] | 970 idl_constructor = interface.constructors[0] |
1022 constructor = generate_constructor(interface, idl_constructor) | 971 constructor = constructor_context(interface, idl_constructor) |
1023 # FIXME(vsm): We drop the name. We don't use this in Dart APIs right now. | 972 # FIXME(vsm): We drop the name. We don't use this in Dart APIs right now. |
1024 # We probably need to encode this somehow to deal with conflicts. | 973 # We probably need to encode this somehow to deal with conflicts. |
1025 # constructor['name'] = extended_attributes['NamedConstructor'] | 974 # constructor['name'] = extended_attributes['NamedConstructor'] |
1026 return constructor | 975 return constructor |
1027 | 976 |
1028 | 977 |
1029 def number_of_required_arguments(constructor): | |
1030 return len([argument for argument in constructor.arguments | |
1031 if not (argument.is_optional and not (('Default' in argument.extended_at
tributes) or argument.default_value))]) | |
1032 | |
1033 | |
1034 def interface_length(interface, constructors): | |
1035 # Docs: http://heycam.github.io/webidl/#es-interface-call | |
1036 if 'EventConstructor' in interface.extended_attributes: | |
1037 return 1 | |
1038 if not constructors: | |
1039 return 0 | |
1040 return min(constructor['number_of_required_arguments'] | |
1041 for constructor in constructors) | |
1042 | |
1043 | |
1044 ################################################################################ | 978 ################################################################################ |
1045 # Special operations (methods) | 979 # Special operations (methods) |
1046 # http://heycam.github.io/webidl/#idl-special-operations | 980 # http://heycam.github.io/webidl/#idl-special-operations |
1047 ################################################################################ | 981 ################################################################################ |
1048 | 982 |
1049 def property_getter(getter, cpp_arguments): | 983 def property_getter(getter, cpp_arguments): |
1050 def is_null_expression(idl_type): | 984 def is_null_expression(idl_type): |
1051 if idl_type.is_union_type: | 985 if idl_type.is_union_type: |
1052 return ' && '.join('!result%sEnabled' % i | 986 return ' && '.join('!result%sEnabled' % i |
1053 for i, _ in enumerate(idl_type.member_types)) | 987 for i, _ in enumerate(idl_type.member_types)) |
1054 if idl_type.name == 'String': | 988 if idl_type.name == 'String': |
1055 # FIXME(vsm): This looks V8 specific. | 989 # FIXME(vsm): This looks V8 specific. |
1056 return 'result.isNull()' | 990 return 'result.isNull()' |
1057 if idl_type.is_interface_type: | 991 if idl_type.is_interface_type: |
1058 return '!result' | 992 return '!result' |
1059 return '' | 993 return '' |
1060 | 994 |
| 995 context = v8_interface.property_getter(getter, []) |
| 996 |
1061 idl_type = getter.idl_type | 997 idl_type = getter.idl_type |
1062 extended_attributes = getter.extended_attributes | 998 extended_attributes = getter.extended_attributes |
1063 is_raises_exception = 'RaisesException' in extended_attributes | 999 is_raises_exception = 'RaisesException' in extended_attributes |
1064 | 1000 |
1065 # FIXME: make more generic, so can use dart_methods.cpp_value | 1001 # FIXME: make more generic, so can use dart_methods.cpp_value |
1066 cpp_method_name = 'receiver->%s' % DartUtilities.cpp_name(getter) | 1002 cpp_method_name = 'receiver->%s' % DartUtilities.cpp_name(getter) |
1067 | 1003 |
1068 if is_raises_exception: | 1004 if is_raises_exception: |
1069 cpp_arguments.append('es') | 1005 cpp_arguments.append('es') |
1070 union_arguments = idl_type.union_arguments | 1006 union_arguments = idl_type.union_arguments |
1071 if union_arguments: | 1007 if union_arguments: |
1072 cpp_arguments.extend(union_arguments) | 1008 cpp_arguments.extend([member_argument['cpp_value'] |
| 1009 for member_argument in union_arguments]) |
1073 | 1010 |
1074 cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments)) | 1011 cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments)) |
1075 | 1012 |
1076 return { | 1013 context.update({ |
1077 'cpp_type': idl_type.cpp_type, | 1014 'cpp_type': idl_type.cpp_type, |
1078 'cpp_value': cpp_value, | 1015 'cpp_value': cpp_value, |
1079 'is_custom': | |
1080 'Custom' in extended_attributes and | |
1081 (not extended_attributes['Custom'] or | |
1082 DartUtilities.has_extended_attribute_value(getter, 'Custom', 'Prope
rtyGetter')), | |
1083 'is_custom_property_enumerator': DartUtilities.has_extended_attribute_va
lue( | |
1084 getter, 'Custom', 'PropertyEnumerator'), | |
1085 'is_custom_property_query': DartUtilities.has_extended_attribute_value( | |
1086 getter, 'Custom', 'PropertyQuery'), | |
1087 'is_enumerable': 'NotEnumerable' not in extended_attributes, | |
1088 'is_null_expression': is_null_expression(idl_type), | 1016 'is_null_expression': is_null_expression(idl_type), |
1089 'is_raises_exception': is_raises_exception, | 1017 'is_raises_exception': is_raises_exception, |
1090 'name': DartUtilities.cpp_name(getter), | 1018 'name': DartUtilities.cpp_name(getter), |
1091 'union_arguments': union_arguments, | 1019 'union_arguments': union_arguments, |
1092 'dart_set_return_value': idl_type.dart_set_return_value('result', | 1020 'dart_set_return_value': idl_type.dart_set_return_value('result', |
1093 extended_attribu
tes=extended_attributes, | 1021 extended_attribu
tes=extended_attributes, |
1094 script_wrappable
='receiver', | 1022 script_wrappable
='receiver', |
1095 release=idl_type
.release)} | 1023 release=idl_type
.release)}) |
| 1024 return context |
1096 | 1025 |
1097 | 1026 |
1098 def property_setter(interface, setter): | 1027 def property_setter(setter): |
| 1028 context = v8_interface.property_setter(setter) |
| 1029 |
1099 idl_type = setter.arguments[1].idl_type | 1030 idl_type = setter.arguments[1].idl_type |
1100 extended_attributes = setter.extended_attributes | 1031 extended_attributes = setter.extended_attributes |
1101 interface_extended_attributes = interface.extended_attributes | 1032 |
1102 is_raises_exception = 'RaisesException' in extended_attributes | 1033 context.update({ |
1103 return { | |
1104 'has_strict_type_checking': | |
1105 'DartStrictTypeChecking' in extended_attributes and | |
1106 idl_type.is_wrapper_type, | |
1107 'idl_type': idl_type.base_type, | |
1108 'is_custom': 'Custom' in extended_attributes, | |
1109 'has_exception_state': is_raises_exception or | |
1110 idl_type.is_integer_type, | |
1111 'is_raises_exception': is_raises_exception, | |
1112 'name': DartUtilities.cpp_name(setter), | |
1113 'dart_value_to_local_cpp_value': idl_type.dart_value_to_local_cpp_value( | 1034 'dart_value_to_local_cpp_value': idl_type.dart_value_to_local_cpp_value( |
1114 interface_extended_attributes, extended_attributes, 'propertyValue',
False), | 1035 extended_attributes, 'propertyValue', False, |
1115 } | 1036 context['has_type_checking_interface']), |
| 1037 }) |
1116 | 1038 |
1117 | 1039 return context |
1118 def property_deleter(deleter): | |
1119 idl_type = deleter.idl_type | |
1120 if str(idl_type) != 'boolean': | |
1121 raise Exception( | |
1122 'Only deleters with boolean type are allowed, but type is "%s"' % | |
1123 idl_type) | |
1124 extended_attributes = deleter.extended_attributes | |
1125 return { | |
1126 'is_custom': 'Custom' in extended_attributes, | |
1127 'is_raises_exception': 'RaisesException' in extended_attributes, | |
1128 'name': DartUtilities.cpp_name(deleter), | |
1129 } | |
1130 | 1040 |
1131 | 1041 |
1132 ################################################################################ | 1042 ################################################################################ |
1133 # Indexed properties | 1043 # Indexed properties |
1134 # http://heycam.github.io/webidl/#idl-indexed-properties | 1044 # http://heycam.github.io/webidl/#idl-indexed-properties |
1135 ################################################################################ | 1045 ################################################################################ |
1136 | 1046 |
1137 def indexed_property_getter(interface): | 1047 def indexed_property_getter(interface): |
1138 try: | 1048 try: |
1139 # Find indexed property getter, if present; has form: | 1049 # Find indexed property getter, if present; has form: |
(...skipping 18 matching lines...) Expand all Loading... |
1158 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE
ARG2) | 1068 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE
ARG2) |
1159 setter = next( | 1069 setter = next( |
1160 method | 1070 method |
1161 for method in interface.operations | 1071 for method in interface.operations |
1162 if ('setter' in method.specials and | 1072 if ('setter' in method.specials and |
1163 len(method.arguments) == 2 and | 1073 len(method.arguments) == 2 and |
1164 str(method.arguments[0].idl_type) == 'unsigned long')) | 1074 str(method.arguments[0].idl_type) == 'unsigned long')) |
1165 except StopIteration: | 1075 except StopIteration: |
1166 return None | 1076 return None |
1167 | 1077 |
1168 return property_setter(interface, setter) | 1078 return property_setter(setter) |
1169 | |
1170 | |
1171 def indexed_property_deleter(interface): | |
1172 try: | |
1173 # Find indexed property deleter, if present; has form: | |
1174 # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG) | |
1175 deleter = next( | |
1176 method | |
1177 for method in interface.operations | |
1178 if ('deleter' in method.specials and | |
1179 len(method.arguments) == 1 and | |
1180 str(method.arguments[0].idl_type) == 'unsigned long')) | |
1181 except StopIteration: | |
1182 return None | |
1183 | |
1184 return property_deleter(deleter) | |
1185 | 1079 |
1186 | 1080 |
1187 ################################################################################ | 1081 ################################################################################ |
1188 # Named properties | 1082 # Named properties |
1189 # http://heycam.github.io/webidl/#idl-named-properties | 1083 # http://heycam.github.io/webidl/#idl-named-properties |
1190 ################################################################################ | 1084 ################################################################################ |
1191 | 1085 |
1192 def named_property_getter(interface): | 1086 def named_property_getter(interface): |
1193 try: | 1087 try: |
1194 # Find named property getter, if present; has form: | 1088 # Find named property getter, if present; has form: |
1195 # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1) | 1089 # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1) |
1196 getter = next( | 1090 getter = next( |
1197 method | 1091 method |
1198 for method in interface.operations | 1092 for method in interface.operations |
1199 if ('getter' in method.specials and | 1093 if ('getter' in method.specials and |
1200 len(method.arguments) == 1 and | 1094 len(method.arguments) == 1 and |
1201 str(method.arguments[0].idl_type) == 'DOMString')) | 1095 str(method.arguments[0].idl_type) == 'DOMString')) |
1202 except StopIteration: | 1096 except StopIteration: |
1203 return None | 1097 return None |
1204 | 1098 |
1205 getter.name = getter.name or 'anonymousNamedGetter' | 1099 getter.name = getter.name or 'anonymousNamedGetter' |
| 1100 |
1206 return property_getter(getter, ['propertyName']) | 1101 return property_getter(getter, ['propertyName']) |
1207 | 1102 |
1208 | 1103 |
1209 def named_property_setter(interface): | 1104 def named_property_setter(interface): |
1210 try: | 1105 try: |
1211 # Find named property setter, if present; has form: | 1106 # Find named property setter, if present; has form: |
1212 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2
) | 1107 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2
) |
1213 setter = next( | 1108 setter = next( |
1214 method | 1109 method |
1215 for method in interface.operations | 1110 for method in interface.operations |
1216 if ('setter' in method.specials and | 1111 if ('setter' in method.specials and |
1217 len(method.arguments) == 2 and | 1112 len(method.arguments) == 2 and |
1218 str(method.arguments[0].idl_type) == 'DOMString')) | 1113 str(method.arguments[0].idl_type) == 'DOMString')) |
1219 except StopIteration: | 1114 except StopIteration: |
1220 return None | 1115 return None |
1221 | 1116 |
1222 return property_setter(interface, setter) | 1117 return property_setter(setter) |
1223 | 1118 |
1224 | 1119 |
1225 def named_property_deleter(interface): | 1120 def generate_native_entries_for_specials(interface, context): |
1226 try: | 1121 def add(prop, name, arity): |
1227 # Find named property deleter, if present; has form: | 1122 if context[prop]: |
1228 # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG) | 1123 if 'native_entries' not in context[prop]: |
1229 deleter = next( | 1124 context[prop].update({'native_entries': []}) |
1230 method | 1125 context[prop]['native_entries'].append( |
1231 for method in interface.operations | 1126 DartUtilities.generate_native_entry( |
1232 if ('deleter' in method.specials and | 1127 interface.name, name, 'Method', False, arity)) |
1233 len(method.arguments) == 1 and | |
1234 str(method.arguments[0].idl_type) == 'DOMString')) | |
1235 except StopIteration: | |
1236 return None | |
1237 | 1128 |
1238 return property_deleter(deleter) | 1129 pre = ['indexed_property', 'named_property'] |
| 1130 post = [('setter', '__setter__', 2), |
| 1131 ('getter', '__getter__', 1), |
| 1132 ('deleter', '__delete__', 1), |
| 1133 ] |
| 1134 props = [(p1 + "_" + p2, name, arity) |
| 1135 for (p1, (p2, name, arity)) in itertools.product(pre, post)] |
| 1136 for t in props: |
| 1137 add(*t) |
| 1138 |
| 1139 for (p, name, arity) in props: |
| 1140 if context[p]: |
| 1141 if context[p].get('is_custom_property_query'): |
| 1142 add(p, '__propertyQuery__', 1) |
OLD | NEW |