Chromium Code Reviews| 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 systems to generate | 6 """This module provides shared functionality for systems to generate |
| 7 Dart APIs from the IDL database.""" | 7 Dart APIs from the IDL database.""" |
| 8 | 8 |
| 9 import re | 9 import re |
| 10 | 10 |
| (...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 714 '"SVGAnimatedListPropertyTearOff.h"', | 714 '"SVGAnimatedListPropertyTearOff.h"', |
| 715 '"SVGTransformListPropertyTearOff.h"', | 715 '"SVGTransformListPropertyTearOff.h"', |
| 716 '"SVGPathSegListPropertyTearOff.h"', | 716 '"SVGPathSegListPropertyTearOff.h"', |
| 717 ] | 717 ] |
| 718 | 718 |
| 719 def GetIDLTypeInfo(idl_type_name): | 719 def GetIDLTypeInfo(idl_type_name): |
| 720 match = re.match(r'sequence<(\w+)>$', idl_type_name) | 720 match = re.match(r'sequence<(\w+)>$', idl_type_name) |
| 721 if match: | 721 if match: |
| 722 return SequenceIDLTypeInfo(idl_type_name, GetIDLTypeInfo(match.group(1))) | 722 return SequenceIDLTypeInfo(idl_type_name, GetIDLTypeInfo(match.group(1))) |
| 723 return _idl_type_registry.get(idl_type_name, IDLTypeInfo(idl_type_name)) | 723 return _idl_type_registry.get(idl_type_name, IDLTypeInfo(idl_type_name)) |
| 724 | |
| 725 def GenerateDispatch(generator, emitter, info, indent, position, overloads): | |
|
podivilov
2012/05/05 16:44:12
I don't think it's a good idea to move this method
sra1
2012/05/05 18:02:06
Pavel, could you say why?
My concern is that nati
podivilov
2012/05/10 10:51:43
We currently use this method in two systems - nati
Anton Muhin
2012/05/10 11:30:13
I am not sure we should be that picky about how ma
Anton Muhin
2012/05/10 11:30:13
Stephen, this CL just gets rid of code duplication
podivilov
2012/05/10 15:57:13
Why is it needed? We are going to get rid of dupli
Anton Muhin
2012/05/10 16:11:55
What do you suggest? Wait until we get rid of it?
podivilov
2012/05/10 16:20:36
Personally, I prefer that you wait until migration
Anton Muhin
2012/05/10 16:24:08
What's ETA? If it's a day or two, I'd better wait
| |
| 726 """Generates a dispatch to one of the overloads. | |
| 727 | |
| 728 Arguments: | |
| 729 emitter: an Emitter for the body of a block of code. | |
| 730 info: the compound information about the operation and its overloads. | |
| 731 indent: an indentation string for generated code. | |
| 732 position: the index of the parameter to dispatch on. | |
| 733 overloads: a list of the remaining IDLOperations to dispatch. | |
| 734 | |
| 735 Returns True if the dispatch can fall through on failure, False if the code | |
| 736 always dispatches. | |
| 737 """ | |
| 738 | |
| 739 def NullCheck(name): | |
| 740 return '%s === null' % name | |
| 741 | |
| 742 def TypeCheck(name, type): | |
| 743 return '%s is %s' % (name, type) | |
| 744 | |
| 745 def ShouldGenerateSingleOperation(): | |
| 746 if position == len(info.param_infos): | |
| 747 if len(overloads) > 1: | |
| 748 raise Exception('Duplicate operations ' + str(overloads)) | |
| 749 return True | |
| 750 | |
| 751 # Check if we dispatch on RequiredCppParameter arguments. In this | |
| 752 # case all trailing arguments must be RequiredCppParameter and there | |
| 753 # is no need in dispatch. | |
| 754 # TODO(antonm): better diagnositics. | |
| 755 if position >= len(overloads[0].arguments): | |
| 756 def IsRequiredCppParameter(arg): | |
| 757 return 'RequiredCppParameter' in arg.ext_attrs | |
| 758 last_overload = overloads[-1] | |
| 759 if (len(last_overload.arguments) > position and | |
| 760 IsRequiredCppParameter(last_overload.arguments[position])): | |
| 761 for overload in overloads: | |
| 762 args = overload.arguments[position:] | |
| 763 if not all([IsRequiredCppParameter(arg) for arg in args]): | |
| 764 raise Exception('Invalid overload for RequiredCppParameter') | |
| 765 return True | |
| 766 | |
| 767 return False | |
| 768 | |
| 769 if ShouldGenerateSingleOperation(): | |
| 770 generator.GenerateSingleOperation(emitter, info, indent, overloads[-1]) | |
| 771 return False | |
| 772 | |
| 773 # FIXME: Consider a simpler dispatch that iterates over the | |
| 774 # overloads and generates an overload specific check. Revisit | |
| 775 # when we move to named optional arguments. | |
| 776 | |
| 777 # Partition the overloads to divide and conquer on the dispatch. | |
| 778 positive = [] | |
| 779 negative = [] | |
| 780 first_overload = overloads[0] | |
| 781 param = info.param_infos[position] | |
| 782 | |
| 783 if position < len(first_overload.arguments): | |
| 784 # FIXME: This will not work if the second overload has a more | |
| 785 # precise type than the first. E.g., | |
| 786 # void foo(Node x); | |
| 787 # void foo(Element x); | |
| 788 type = DartType(first_overload.arguments[position].type.id) | |
| 789 test = TypeCheck(param.name, type) | |
| 790 pred = lambda op: len(op.arguments) > position and DartType(op.arguments[pos ition].type.id) == type | |
| 791 else: | |
| 792 type = None | |
| 793 test = NullCheck(param.name) | |
| 794 pred = lambda op: position >= len(op.arguments) | |
| 795 | |
| 796 for overload in overloads: | |
| 797 if pred(overload): | |
| 798 positive.append(overload) | |
| 799 else: | |
| 800 negative.append(overload) | |
| 801 | |
| 802 if positive and negative: | |
| 803 (true_code, false_code) = emitter.Emit( | |
| 804 '$(INDENT)if ($COND) {\n' | |
| 805 '$!TRUE' | |
| 806 '$(INDENT)} else {\n' | |
| 807 '$!FALSE' | |
| 808 '$(INDENT)}\n', | |
| 809 COND=test, INDENT=indent) | |
| 810 fallthrough1 = GenerateDispatch(generator, | |
| 811 true_code, info, indent + ' ', position + 1, positive) | |
| 812 fallthrough2 = GenerateDispatch(generator, | |
| 813 false_code, info, indent + ' ', position, negative) | |
| 814 return fallthrough1 or fallthrough2 | |
| 815 | |
| 816 if negative: | |
| 817 raise Exception('Internal error, must be all positive') | |
| 818 | |
| 819 # All overloads require the same test. Do we bother? | |
| 820 | |
| 821 # If the test is the same as the method's formal parameter then checked mode | |
| 822 # will have done the test already. (It could be null too but we ignore that | |
| 823 # case since all the overload behave the same and we don't know which types | |
| 824 # in the IDL are not nullable.) | |
| 825 if type == param.dart_type: | |
| 826 return GenerateDispatch(generator, | |
| 827 emitter, info, indent, position + 1, positive) | |
| 828 | |
| 829 # Otherwise the overloads have the same type but the type is a subtype of | |
| 830 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
| 831 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
| 832 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
| 833 # that Y = Z-X, so we need to check for Y. | |
| 834 true_code = emitter.Emit( | |
| 835 '$(INDENT)if ($COND) {\n' | |
| 836 '$!TRUE' | |
| 837 '$(INDENT)}\n', | |
| 838 COND=test, INDENT=indent) | |
| 839 GenerateDispatch(generator, | |
| 840 true_code, info, indent + ' ', position + 1, positive) | |
| 841 return True | |
| OLD | NEW |