Chromium Code Reviews| 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 # coding=utf-8 |
| 3 # | 3 # |
| 4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
| 5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
| 6 # met: | 6 # met: |
| 7 # | 7 # |
| 8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
| 9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
| 10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
| (...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 675 def resolution_tests_methods(effective_overloads): | 675 def resolution_tests_methods(effective_overloads): |
| 676 """Yields resolution test and associated method, in resolution order, for ef fective overloads of a given length. | 676 """Yields resolution test and associated method, in resolution order, for ef fective overloads of a given length. |
| 677 | 677 |
| 678 This is the heart of the resolution algorithm. | 678 This is the heart of the resolution algorithm. |
| 679 http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm | 679 http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm |
| 680 | 680 |
| 681 Note that a given method can be listed multiple times, with different tests! | 681 Note that a given method can be listed multiple times, with different tests! |
| 682 This is to handle implicit type conversion. | 682 This is to handle implicit type conversion. |
| 683 | 683 |
| 684 Returns: | 684 Returns: |
| 685 [(test, method)] | 685 [(test, method)] |
|
bashi
2014/10/15 00:02:12
Could you update this comment?
| |
| 686 """ | 686 """ |
| 687 methods = [effective_overload[0] | 687 methods = [effective_overload[0] |
| 688 for effective_overload in effective_overloads] | 688 for effective_overload in effective_overloads] |
| 689 if len(methods) == 1: | 689 if len(methods) == 1: |
| 690 # If only one method with a given length, no test needed | 690 # If only one method with a given length, no test needed |
| 691 yield 'true', methods[0] | 691 yield 'true', methods[0], -1 |
| 692 return | 692 return |
| 693 | 693 |
| 694 # 6. If there is more than one entry in S, then set d to be the | 694 # 6. If there is more than one entry in S, then set d to be the |
| 695 # distinguishing argument index for the entries of S. | 695 # distinguishing argument index for the entries of S. |
| 696 index = distinguishing_argument_index(effective_overloads) | 696 index = distinguishing_argument_index(effective_overloads) |
| 697 # (7-9 are for handling |undefined| values for optional arguments before | 697 # (7-9 are for handling |undefined| values for optional arguments before |
| 698 # the distinguishing argument (as “missing”), so you can specify only some | 698 # the distinguishing argument (as “missing”), so you can specify only some |
| 699 # optional arguments. We don’t support this, so we skip these steps.) | 699 # optional arguments. We don’t support this, so we skip these steps.) |
| 700 # 10. If i = d, then: | 700 # 10. If i = d, then: |
| 701 # (d is the distinguishing argument index) | 701 # (d is the distinguishing argument index) |
| 702 # 1. Let V be argi. | 702 # 1. Let V be argi. |
| 703 # Note: This is the argument that will be used to resolve which | 703 # Note: This is the argument that will be used to resolve which |
| 704 # overload is selected. | 704 # overload is selected. |
| 705 cpp_value = 'info[%s]' % index | 705 cpp_value = 'info[%s]' % index |
| 706 | 706 |
| 707 # Extract argument and IDL type to simplify accessing these in each loop. | 707 # Extract argument and IDL type to simplify accessing these in each loop. |
| 708 arguments = [method['arguments'][index] for method in methods] | 708 arguments = [method['arguments'][index] for method in methods] |
| 709 arguments_methods = zip(arguments, methods) | 709 arguments_methods = zip(arguments, methods) |
| 710 idl_types = [argument['idl_type_object'] for argument in arguments] | 710 idl_types = [argument['idl_type_object'] for argument in arguments] |
| 711 idl_types_methods = zip(idl_types, methods) | 711 idl_types_methods = zip(idl_types, methods) |
| 712 | 712 |
| 713 for argument in arguments: | |
| 714 argument['is_distinguishing_argument'] = True | |
| 715 | |
| 713 # We can’t do a single loop through all methods or simply sort them, because | 716 # We can’t do a single loop through all methods or simply sort them, because |
| 714 # a method may be listed in multiple steps of the resolution algorithm, and | 717 # a method may be listed in multiple steps of the resolution algorithm, and |
| 715 # which test to apply differs depending on the step. | 718 # which test to apply differs depending on the step. |
| 716 # | 719 # |
| 717 # Instead, we need to go through all methods at each step, either finding | 720 # Instead, we need to go through all methods at each step, either finding |
| 718 # first match (if only one test is allowed) or filtering to matches (if | 721 # first match (if only one test is allowed) or filtering to matches (if |
| 719 # multiple tests are allowed), and generating an appropriate tests. | 722 # multiple tests are allowed), and generating an appropriate tests. |
| 720 | 723 |
| 721 # 2. If V is undefined, and there is an entry in S whose list of | 724 # 2. If V is undefined, and there is an entry in S whose list of |
| 722 # optionality values has “optional” at index i, then remove from S all | 725 # optionality values has “optional” at index i, then remove from S all |
| 723 # other entries. | 726 # other entries. |
| 724 try: | 727 try: |
| 725 method = next(method for argument, method in arguments_methods | 728 method = next(method for argument, method in arguments_methods |
| 726 if argument['is_optional']) | 729 if argument['is_optional']) |
| 727 test = '%s->IsUndefined()' % cpp_value | 730 test = '%s->IsUndefined()' % cpp_value |
| 728 yield test, method | 731 yield test, method, -1 |
| 729 except StopIteration: | 732 except StopIteration: |
| 730 pass | 733 pass |
| 731 | 734 |
| 732 # 3. Otherwise: if V is null or undefined, and there is an entry in S that | 735 # 3. Otherwise: if V is null or undefined, and there is an entry in S that |
| 733 # has one of the following types at position i of its type list, | 736 # has one of the following types at position i of its type list, |
| 734 # • a nullable type | 737 # • a nullable type |
| 735 try: | 738 try: |
| 736 method = next(method for idl_type, method in idl_types_methods | 739 method = next(method for idl_type, method in idl_types_methods |
| 737 if idl_type.is_nullable) | 740 if idl_type.is_nullable) |
| 738 test = 'isUndefinedOrNull(%s)' % cpp_value | 741 test = 'isUndefinedOrNull(%s)' % cpp_value |
| 739 yield test, method | 742 yield test, method, -1 |
| 740 except StopIteration: | 743 except StopIteration: |
| 741 pass | 744 pass |
| 742 | 745 |
| 743 # 4. Otherwise: if V is a platform object – but not a platform array | 746 # 4. Otherwise: if V is a platform object – but not a platform array |
| 744 # object – and there is an entry in S that has one of the following | 747 # object – and there is an entry in S that has one of the following |
| 745 # types at position i of its type list, | 748 # types at position i of its type list, |
| 746 # • an interface type that V implements | 749 # • an interface type that V implements |
| 747 # (Unlike most of these tests, this can return multiple methods, since we | 750 # (Unlike most of these tests, this can return multiple methods, since we |
| 748 # test if it implements an interface. Thus we need a for loop, not a next.) | 751 # test if it implements an interface. Thus we need a for loop, not a next.) |
| 749 # (We distinguish wrapper types from built-in interface types.) | 752 # (We distinguish wrapper types from built-in interface types.) |
| 750 for idl_type, method in ((idl_type, method) | 753 for idl_type, method in ((idl_type, method) |
| 751 for idl_type, method in idl_types_methods | 754 for idl_type, method in idl_types_methods |
| 752 if idl_type.is_wrapper_type): | 755 if idl_type.is_wrapper_type): |
| 753 test = 'V8{idl_type}::hasInstance({cpp_value}, info.GetIsolate())'.forma t(idl_type=idl_type.base_type, cpp_value=cpp_value) | 756 test = 'V8{idl_type}::hasInstance({cpp_value}, info.GetIsolate())'.forma t(idl_type=idl_type.base_type, cpp_value=cpp_value) |
| 754 yield test, method | 757 yield test, method, index |
| 755 | 758 |
| 756 # 8. Otherwise: if V is any kind of object except for a native Date object, | 759 # 8. Otherwise: if V is any kind of object except for a native Date object, |
| 757 # a native RegExp object, and there is an entry in S that has one of the | 760 # a native RegExp object, and there is an entry in S that has one of the |
| 758 # following types at position i of its type list, | 761 # following types at position i of its type list, |
| 759 # • an array type | 762 # • an array type |
| 760 # • a sequence type | 763 # • a sequence type |
| 761 # ... | 764 # ... |
| 762 # • a dictionary | 765 # • a dictionary |
| 763 # | 766 # |
| 764 # FIXME: | 767 # FIXME: |
| 765 # We don't strictly follow the algorithm here. The algorithm says "remove | 768 # We don't strictly follow the algorithm here. The algorithm says "remove |
| 766 # all other entries" if there is "one entry" matching, but we yield all | 769 # all other entries" if there is "one entry" matching, but we yield all |
| 767 # entries to support following constructors: | 770 # entries to support following constructors: |
| 768 # [constructor(sequence<DOMString> arg), constructor(Dictionary arg)] | 771 # [constructor(sequence<DOMString> arg), constructor(Dictionary arg)] |
| 769 # interface I { ... } | 772 # interface I { ... } |
| 770 # (Need to check array types before objects because an array is an object) | 773 # (Need to check array types before objects because an array is an object) |
| 771 for idl_type, method in idl_types_methods: | 774 for idl_type, method in idl_types_methods: |
| 772 if idl_type.native_array_element_type: | 775 if idl_type.native_array_element_type: |
| 773 # (We test for Array instead of generic Object to type-check.) | 776 # (We test for Array instead of generic Object to type-check.) |
| 774 # FIXME: test for Object during resolution, then have type check for | 777 # FIXME: test for Object during resolution, then have type check for |
| 775 # Array in overloaded method: http://crbug.com/262383 | 778 # Array in overloaded method: http://crbug.com/262383 |
| 776 yield '%s->IsArray()' % cpp_value, method | 779 yield '%s->IsArray()' % cpp_value, method, index |
| 777 for idl_type, method in idl_types_methods: | 780 for idl_type, method in idl_types_methods: |
| 778 if idl_type.is_dictionary or idl_type.name == 'Dictionary': | 781 if idl_type.is_dictionary or idl_type.name == 'Dictionary': |
| 779 # FIXME: should be '{1}->IsObject() && !{1}->IsDate() && !{1}->IsReg Exp()'.format(cpp_value) | 782 # FIXME: should be '{1}->IsObject() && !{1}->IsDate() && !{1}->IsReg Exp()'.format(cpp_value) |
| 780 # FIXME: the IsDate and IsRegExp checks can be skipped if we've | 783 # FIXME: the IsDate and IsRegExp checks can be skipped if we've |
| 781 # already generated tests for them. | 784 # already generated tests for them. |
| 782 yield '%s->IsObject()' % cpp_value, method | 785 yield '%s->IsObject()' % cpp_value, method, index |
| 783 | 786 |
| 784 # (Check for exact type matches before performing automatic type conversion; | 787 # (Check for exact type matches before performing automatic type conversion; |
| 785 # only needed if distinguishing between primitive types.) | 788 # only needed if distinguishing between primitive types.) |
| 786 if len([idl_type.is_primitive_type for idl_type in idl_types]) > 1: | 789 if len([idl_type.is_primitive_type for idl_type in idl_types]) > 1: |
| 787 # (Only needed if match in step 11, otherwise redundant.) | 790 # (Only needed if match in step 11, otherwise redundant.) |
| 788 if any(idl_type.is_string_type or idl_type.is_enum | 791 if any(idl_type.is_string_type or idl_type.is_enum |
| 789 for idl_type in idl_types): | 792 for idl_type in idl_types): |
| 790 # 10. Otherwise: if V is a Number value, and there is an entry in S | 793 # 10. Otherwise: if V is a Number value, and there is an entry in S |
| 791 # that has one of the following types at position i of its type | 794 # that has one of the following types at position i of its type |
| 792 # list, | 795 # list, |
| 793 # • a numeric type | 796 # • a numeric type |
| 794 try: | 797 try: |
| 795 method = next(method for idl_type, method in idl_types_methods | 798 method = next(method for idl_type, method in idl_types_methods |
| 796 if idl_type.is_numeric_type) | 799 if idl_type.is_numeric_type) |
| 797 test = '%s->IsNumber()' % cpp_value | 800 test = '%s->IsNumber()' % cpp_value |
| 798 yield test, method | 801 yield test, method, index |
| 799 except StopIteration: | 802 except StopIteration: |
| 800 pass | 803 pass |
| 801 | 804 |
| 802 # (Perform automatic type conversion, in order. If any of these match, | 805 # (Perform automatic type conversion, in order. If any of these match, |
| 803 # that’s the end, and no other tests are needed.) To keep this code simple, | 806 # that’s the end, and no other tests are needed.) To keep this code simple, |
| 804 # we rely on the C++ compiler's dead code elimination to deal with the | 807 # we rely on the C++ compiler's dead code elimination to deal with the |
| 805 # redundancy if both cases below trigger. | 808 # redundancy if both cases below trigger. |
| 806 | 809 |
| 807 # 11. Otherwise: if there is an entry in S that has one of the following | 810 # 11. Otherwise: if there is an entry in S that has one of the following |
| 808 # types at position i of its type list, | 811 # types at position i of its type list, |
| 809 # • DOMString | 812 # • DOMString |
| 810 # • ByteString | 813 # • ByteString |
| 811 # • ScalarValueString [a DOMString typedef, per definition.] | 814 # • ScalarValueString [a DOMString typedef, per definition.] |
| 812 # • an enumeration type | 815 # • an enumeration type |
| 813 try: | 816 try: |
| 814 method = next(method for idl_type, method in idl_types_methods | 817 method = next(method for idl_type, method in idl_types_methods |
| 815 if idl_type.is_string_type or idl_type.is_enum) | 818 if idl_type.is_string_type or idl_type.is_enum) |
| 816 yield 'true', method | 819 yield 'true', method, -1 |
| 817 except StopIteration: | 820 except StopIteration: |
| 818 pass | 821 pass |
| 819 | 822 |
| 820 # 12. Otherwise: if there is an entry in S that has one of the following | 823 # 12. Otherwise: if there is an entry in S that has one of the following |
| 821 # types at position i of its type list, | 824 # types at position i of its type list, |
| 822 # • a numeric type | 825 # • a numeric type |
| 823 try: | 826 try: |
| 824 method = next(method for idl_type, method in idl_types_methods | 827 method = next(method for idl_type, method in idl_types_methods |
| 825 if idl_type.is_numeric_type) | 828 if idl_type.is_numeric_type) |
| 826 yield 'true', method | 829 yield 'true', method, -1 |
| 827 except StopIteration: | 830 except StopIteration: |
| 828 pass | 831 pass |
| 829 | 832 |
| 830 | 833 |
| 831 ################################################################################ | 834 ################################################################################ |
| 832 # Utility functions | 835 # Utility functions |
| 833 ################################################################################ | 836 ################################################################################ |
| 834 | 837 |
| 835 def Counter(iterable): | 838 def Counter(iterable): |
| 836 # Once using Python 2.7, using collections.Counter | 839 # Once using Python 2.7, using collections.Counter |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1133 deleter = next( | 1136 deleter = next( |
| 1134 method | 1137 method |
| 1135 for method in interface.operations | 1138 for method in interface.operations |
| 1136 if ('deleter' in method.specials and | 1139 if ('deleter' in method.specials and |
| 1137 len(method.arguments) == 1 and | 1140 len(method.arguments) == 1 and |
| 1138 str(method.arguments[0].idl_type) == 'DOMString')) | 1141 str(method.arguments[0].idl_type) == 'DOMString')) |
| 1139 except StopIteration: | 1142 except StopIteration: |
| 1140 return None | 1143 return None |
| 1141 | 1144 |
| 1142 return property_deleter(deleter) | 1145 return property_deleter(deleter) |
| OLD | NEW |