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 the systems to generate | 6 """This module provides shared functionality for the systems to generate |
| 7 native binding from the IDL database.""" | 7 native binding from the IDL database.""" |
| 8 | 8 |
| 9 import emitter | 9 import emitter |
| 10 import os | 10 import os |
| (...skipping 847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 858 body = self._members_emitter.Emit( | 858 body = self._members_emitter.Emit( |
| 859 '\n' | 859 '\n' |
| 860 ' $MODIFIER$TYPE $NAME($PARAMETERS) {\n' | 860 ' $MODIFIER$TYPE $NAME($PARAMETERS) {\n' |
| 861 '$!BODY' | 861 '$!BODY' |
| 862 ' }\n', | 862 ' }\n', |
| 863 MODIFIER=modifier, | 863 MODIFIER=modifier, |
| 864 TYPE=self._DartType(info.type_name), | 864 TYPE=self._DartType(info.type_name), |
| 865 NAME=info.name, | 865 NAME=info.name, |
| 866 PARAMETERS=parameters) | 866 PARAMETERS=parameters) |
| 867 | 867 |
| 868 # Process in order of ascending number of arguments to ensure missing | |
| 869 # optional arguments are processed early. | |
| 870 overloads = sorted(info.overloads, | |
| 871 key=lambda overload: len(overload.arguments)) | |
| 872 self._native_version = 0 | 868 self._native_version = 0 |
| 873 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | 869 overloads = self.CombineOverloads(info.overloads) |
| 870 fallthrough = self.GenerateDispatch(body, info, ' ', overloads) | |
| 874 if fallthrough: | 871 if fallthrough: |
| 875 body.Emit(' throw "Incorrect number or type of arguments";\n'); | 872 body.Emit(' throw "Incorrect number or type of arguments";\n'); |
| 876 | 873 |
| 877 def GenerateDispatch(self, emitter, info, indent, position, overloads): | 874 def CombineOverloads(self, overloads): |
| 875 # Combine overloads that can be implemented by the same native method. This | |
| 876 # undoes the expansion of optional arguments into multiple overloads unless | |
| 877 # IDL merging has made the overloads necessary. Starting with overload with | |
| 878 # no optional arguments and grow it by adding optional arguments, then the | |
| 879 # longest overload can serve for all the shorter ones. | |
| 880 out = [] | |
| 881 seed_index = 0 | |
| 882 while seed_index < len(overloads): | |
| 883 seed = overloads[seed_index] | |
| 884 if len(seed.arguments) > 0 and seed.arguments[-1].is_optional: | |
|
Anton Muhin
2012/05/25 10:46:34
when this condition fires?
| |
| 885 # Must start with no optional arguments. | |
| 886 out.append(seed) | |
| 887 seed_index += 1 | |
| 888 continue | |
| 889 | |
| 890 prev = seed | |
| 891 probe_index = seed_index + 1 | |
| 892 while probe_index < len(overloads): | |
| 893 probe = overloads[probe_index] | |
| 894 # Check that 'probe' extends 'prev' by one optional argument. | |
| 895 if len(probe.arguments) != len(prev.arguments) + 1: | |
| 896 break | |
| 897 if probe.arguments[:-1] != prev.arguments: | |
|
Anton Muhin
2012/05/25 10:46:34
that should cover the condition above, no? as we
| |
| 898 break | |
| 899 if not probe.arguments[-1].is_optional: | |
| 900 break | |
| 901 # See Issue 3177. This test against known implemented types is to | |
|
Anton Muhin
2012/05/25 10:46:34
Stephen, I don't think we need this code, we shoul
| |
| 902 # prevent combining a possibly unimplemented type. Combining with an | |
| 903 # unimplemented type will cause all set of combined overloads to become | |
| 904 # 'unimplemented', even if no argument is passed to the the | |
| 905 # unimplemented parameter. | |
| 906 if DartType(probe.arguments[-1].type.id) not in [ | |
| 907 'String', 'int', 'num', 'double', 'bool', | |
| 908 'IDBKeyRange']: | |
| 909 break | |
| 910 probe_index += 1 | |
| 911 prev = probe | |
| 912 out.append(prev) | |
| 913 seed_index = probe_index | |
| 914 | |
| 915 return out | |
| 916 | |
| 917 def PrintOverloadsComment(self, emitter, info, indent, note, overloads): | |
| 918 emitter.Emit('$(INDENT)//$NOTE\n', INDENT=indent, NOTE=note) | |
| 919 for operation in overloads: | |
| 920 params = ', '.join([ | |
| 921 ('[Optional] ' if arg.is_optional else '') + DartType(arg.type.id) + ' ' | |
| 922 + arg.id for arg in operation.arguments]) | |
| 923 emitter.Emit('$(INDENT)// $NAME($PARAMS)\n', | |
| 924 INDENT=indent, | |
| 925 NAME=info.name, | |
| 926 PARAMS=params) | |
| 927 emitter.Emit('$(INDENT)//\n', INDENT=indent) | |
| 928 | |
| 929 def GenerateDispatch(self, emitter, info, indent, overloads): | |
| 878 """Generates a dispatch to one of the overloads. | 930 """Generates a dispatch to one of the overloads. |
| 879 | 931 |
| 880 Arguments: | 932 Arguments: |
| 881 emitter: an Emitter for the body of a block of code. | 933 emitter: an Emitter for the body of a block of code. |
| 882 info: the compound information about the operation and its overloads. | 934 info: the compound information about the operation and its overloads. |
| 883 indent: an indentation string for generated code. | 935 indent: an indentation string for generated code. |
| 884 position: the index of the parameter to dispatch on. | 936 position: the index of the parameter to dispatch on. |
| 885 overloads: a list of the remaining IDLOperations to dispatch. | 937 overloads: a list of the IDLOperations to dispatch. |
| 886 | 938 |
| 887 Returns True if the dispatch can fall through on failure, False if the code | 939 Returns True if the dispatch can fall through on failure, False if the code |
| 888 always dispatches. | 940 always dispatches. |
| 889 """ | 941 """ |
| 890 | 942 |
| 891 def NullCheck(name): | 943 def NullCheck(name): |
| 892 return '%s === null' % name | 944 return '%s === null' % name |
| 893 | 945 |
| 894 def TypeCheck(name, type): | 946 def TypeCheck(name, type): |
| 895 return '%s is %s' % (name, type) | 947 return '%s is %s' % (name, type) |
| 896 | 948 |
| 897 def ShouldGenerateSingleOperation(): | 949 def IsNullable(type): |
| 898 if position == len(info.param_infos): | 950 #return type != 'int' and type != 'num' |
| 899 if len(overloads) > 1: | 951 return True |
| 900 raise Exception('Duplicate operations ' + str(overloads)) | |
| 901 return True | |
| 902 | 952 |
| 903 # Check if we dispatch on RequiredCppParameter arguments. In this | 953 def PickRequiredCppSingleOperation(): |
| 904 # case all trailing arguments must be RequiredCppParameter and there | 954 # Returns a special case single operation, or None. Check if we dispatch |
| 905 # is no need in dispatch. | 955 # on RequiredCppParameter arguments. In this case all trailing arguments |
| 906 # TODO(antonm): better diagnositics. | 956 # must be RequiredCppParameter and there is no need in dispatch. |
| 907 if position >= len(overloads[0].arguments): | 957 def IsRequiredCppParameter(arg): |
| 908 def IsRequiredCppParameter(arg): | 958 return 'RequiredCppParameter' in arg.ext_attrs |
| 909 return 'RequiredCppParameter' in arg.ext_attrs | 959 def HasRequiredCppParameters(op): |
| 910 last_overload = overloads[-1] | 960 matches = filter(IsRequiredCppParameter, op.arguments) |
| 911 if (len(last_overload.arguments) > position and | 961 if matches: |
| 912 IsRequiredCppParameter(last_overload.arguments[position])): | 962 # Validate all the RequiredCppParameter ones are at the end. |
| 913 for overload in overloads: | 963 rematches = filter(IsRequiredCppParameter, |
| 914 args = overload.arguments[position:] | 964 op.arguments[len(op.arguments) - len(matches):]) |
| 915 if not all([IsRequiredCppParameter(arg) for arg in args]): | 965 if len(matches) != len(rematches): |
|
Anton Muhin
2012/05/25 10:46:34
okay, but here
if not all(IsRequiredCppParameter
| |
| 916 raise Exception('Invalid overload for RequiredCppParameter') | 966 raise Exception('Invalid RequiredCppParameter - all subsequent ' |
| 967 'parameters must also be RequiredCppParameter.') | |
| 917 return True | 968 return True |
| 969 return False | |
| 970 if any(HasRequiredCppParameters(op) for op in overloads): | |
| 971 longest = max(overloads, key=lambda op: len(op.arguments)) | |
| 972 # Validate all other overloads are prefixes. | |
| 973 for op in overloads: | |
| 974 for (index, arg) in enumerate(op.arguments): | |
| 975 type1 = arg.type.id | |
| 976 type2 = longest.arguments[index].type.id | |
| 977 if type1 != type2: | |
| 978 raise Exception( | |
| 979 'Overloads for method %s with RequiredCppParameter have ' | |
| 980 'inconsistent types %s and %s for parameter #%s' % | |
| 981 (info.name, type1, type2, index)) | |
| 982 return longest | |
| 983 return None | |
| 918 | 984 |
| 985 single_operation = PickRequiredCppSingleOperation() | |
| 986 if single_operation: | |
| 987 self.GenerateSingleOperation(emitter, info, indent, single_operation) | |
| 919 return False | 988 return False |
| 920 | 989 |
| 921 if ShouldGenerateSingleOperation(): | 990 # Print just the interesting sets of overloads. |
| 922 self.GenerateSingleOperation(emitter, info, indent, overloads[-1]) | 991 if len(overloads) > 1 or len(info.overloads) > 1: |
| 923 return False | 992 self.PrintOverloadsComment(emitter, info, indent, '', info.overloads) |
| 993 if overloads != info.overloads: | |
| 994 self.PrintOverloadsComment(emitter, info, indent, ' -- reduced:', | |
| 995 overloads) | |
| 924 | 996 |
| 925 # FIXME: Consider a simpler dispatch that iterates over the | 997 # Match each operation in turn. |
| 926 # overloads and generates an overload specific check. Revisit | 998 # TODO: Optimize the dispatch to avoid repeated tests. |
| 927 # when we move to named optional arguments. | 999 fallthrough = True |
| 928 | 1000 for operation in overloads: |
| 929 # Partition the overloads to divide and conquer on the dispatch. | 1001 tests = [] |
| 930 positive = [] | 1002 for (position, param) in enumerate(info.param_infos): |
| 931 negative = [] | 1003 if position < len(operation.arguments): |
| 932 first_overload = overloads[0] | 1004 arg = operation.arguments[position] |
| 933 param = info.param_infos[position] | 1005 dart_type = DartType(arg.type.id) |
| 934 | 1006 if dart_type == param.dart_type: |
|
Anton Muhin
2012/05/25 10:46:34
won't it be more straightforward to check param.de
| |
| 935 if position < len(first_overload.arguments): | 1007 # The overload type matches the method parameter type exactly. We |
| 936 # FIXME: This will not work if the second overload has a more | 1008 # will have already tested this type in checked mode, and the target |
| 937 # precise type than the first. E.g., | 1009 # will expect (i.e. check) this type. This case happens when all |
| 938 # void foo(Node x); | 1010 # the overloads have the same type in this position, including the |
| 939 # void foo(Element x); | 1011 # trivial case of one overload. |
| 940 type = self._DartType(first_overload.arguments[position].type.id) | 1012 test = None |
| 941 test = TypeCheck(param.name, type) | 1013 else: |
| 942 pred = lambda op: len(op.arguments) > position and self._DartType(op.argum ents[position].type.id) == type | 1014 test = TypeCheck(param.name, dart_type) |
|
Anton Muhin
2012/05/25 10:46:34
we have single call site for TypeCheck/NullCheck,
| |
| 943 else: | 1015 if IsNullable(dart_type) or arg.is_optional: |
| 944 type = None | 1016 test = '(%s || %s)' % (NullCheck(param.name), test) |
|
Anton Muhin
2012/05/25 10:46:34
any chances it might be incorrect in the following
| |
| 945 test = NullCheck(param.name) | 1017 else: |
| 946 pred = lambda op: position >= len(op.arguments) | 1018 test = NullCheck(param.name) |
| 947 | 1019 if test: |
|
Anton Muhin
2012/05/25 10:46:34
why this check, cannot you populate tests just in
| |
| 948 for overload in overloads: | 1020 tests.append(test) |
| 949 if pred(overload): | 1021 if tests: |
|
Anton Muhin
2012/05/25 10:46:34
Please, add a blank line
| |
| 950 positive.append(overload) | 1022 cond = ' && '.join(tests) |
| 1023 if len(cond) + len(indent) + 7 > 80: | |
|
Anton Muhin
2012/05/25 10:46:34
I wouldn't complicate this logic to keep 80 constr
| |
| 1024 cond = (' &&\n' + indent + ' ').join(tests) | |
| 1025 call = emitter.Emit( | |
| 1026 '$(INDENT)if ($COND) {\n' | |
| 1027 '$!CALL' | |
| 1028 '$(INDENT)}\n', | |
| 1029 COND=cond, | |
| 1030 INDENT=indent) | |
| 1031 self.GenerateSingleOperation(call, info, indent + ' ', operation) | |
| 951 else: | 1032 else: |
| 952 negative.append(overload) | 1033 self.GenerateSingleOperation(emitter, info, indent, operation) |
| 953 | 1034 fallthrough = False |
|
Anton Muhin
2012/05/25 10:46:34
you probably want to return from here, correct, ma
| |
| 954 if positive and negative: | 1035 return fallthrough |
| 955 (true_code, false_code) = emitter.Emit( | |
| 956 '$(INDENT)if ($COND) {\n' | |
| 957 '$!TRUE' | |
| 958 '$(INDENT)} else {\n' | |
| 959 '$!FALSE' | |
| 960 '$(INDENT)}\n', | |
| 961 COND=test, INDENT=indent) | |
| 962 fallthrough1 = self.GenerateDispatch( | |
| 963 true_code, info, indent + ' ', position + 1, positive) | |
| 964 fallthrough2 = self.GenerateDispatch( | |
| 965 false_code, info, indent + ' ', position, negative) | |
| 966 return fallthrough1 or fallthrough2 | |
| 967 | |
| 968 if negative: | |
| 969 raise Exception('Internal error, must be all positive') | |
| 970 | |
| 971 # All overloads require the same test. Do we bother? | |
| 972 | |
| 973 # If the test is the same as the method's formal parameter then checked mode | |
| 974 # will have done the test already. (It could be null too but we ignore that | |
| 975 # case since all the overload behave the same and we don't know which types | |
| 976 # in the IDL are not nullable.) | |
| 977 if type == param.dart_type: | |
| 978 return self.GenerateDispatch( | |
| 979 emitter, info, indent, position + 1, positive) | |
| 980 | |
| 981 # Otherwise the overloads have the same type but the type is a subtype of | |
| 982 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
| 983 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
| 984 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
| 985 # that Y = Z-X, so we need to check for Y. | |
| 986 true_code = emitter.Emit( | |
| 987 '$(INDENT)if ($COND) {\n' | |
| 988 '$!TRUE' | |
| 989 '$(INDENT)}\n', | |
| 990 COND=test, INDENT=indent) | |
| 991 self.GenerateDispatch( | |
| 992 true_code, info, indent + ' ', position + 1, positive) | |
| 993 return True | |
| 994 | 1036 |
| 995 def AddOperation(self, info): | 1037 def AddOperation(self, info): |
| 996 self._AddOperation(info) | 1038 self._AddOperation(info) |
| 997 | 1039 |
| 998 def AddStaticOperation(self, info): | 1040 def AddStaticOperation(self, info): |
| 999 self._AddOperation(info) | 1041 self._AddOperation(info) |
| 1000 | 1042 |
| 1001 def AddSecondaryOperation(self, interface, info): | 1043 def AddSecondaryOperation(self, interface, info): |
| 1002 self.AddOperation(info) | 1044 self.AddOperation(info) |
| 1003 | 1045 |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1237 for parent in interface.parents: | 1279 for parent in interface.parents: |
| 1238 parent_name = parent.type.id | 1280 parent_name = parent.type.id |
| 1239 if not database.HasInterface(parent.type.id): | 1281 if not database.HasInterface(parent.type.id): |
| 1240 continue | 1282 continue |
| 1241 parent_interface = database.GetInterface(parent.type.id) | 1283 parent_interface = database.GetInterface(parent.type.id) |
| 1242 if callback(parent_interface): | 1284 if callback(parent_interface): |
| 1243 return parent_interface | 1285 return parent_interface |
| 1244 parent_interface = _FindParent(parent_interface, database, callback) | 1286 parent_interface = _FindParent(parent_interface, database, callback) |
| 1245 if parent_interface: | 1287 if parent_interface: |
| 1246 return parent_interface | 1288 return parent_interface |
| OLD | NEW |