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 |