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 821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 832 body = self._members_emitter.Emit( | 832 body = self._members_emitter.Emit( |
| 833 '\n' | 833 '\n' |
| 834 ' $MODIFIER$TYPE $NAME($PARAMETERS) {\n' | 834 ' $MODIFIER$TYPE $NAME($PARAMETERS) {\n' |
| 835 '$!BODY' | 835 '$!BODY' |
| 836 ' }\n', | 836 ' }\n', |
| 837 MODIFIER=modifier, | 837 MODIFIER=modifier, |
| 838 TYPE=info.type_name, | 838 TYPE=info.type_name, |
| 839 NAME=info.name, | 839 NAME=info.name, |
| 840 PARAMETERS=info.ParametersImplementationDeclaration()) | 840 PARAMETERS=info.ParametersImplementationDeclaration()) |
| 841 | 841 |
| 842 # Process in order of ascending number of arguments to ensure missing | |
| 843 # optional arguments are processed early. | |
| 844 overloads = sorted(info.overloads, | |
| 845 key=lambda overload: len(overload.arguments)) | |
| 846 self._native_version = 0 | 842 self._native_version = 0 |
| 847 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | 843 if info.name in ['createObjectStore']: |
|
Anton Muhin
2012/05/23 14:43:33
why?
sra1
2012/05/25 01:40:05
Sorry, debugging. removed
| |
| 844 overloads = info.overloads | |
| 845 else: | |
| 846 overloads = self.CombineOverloads(info.overloads) | |
| 847 fallthrough = self.GenerateDispatch(body, info, ' ', overloads) | |
| 848 if fallthrough: | 848 if fallthrough: |
| 849 body.Emit(' throw "Incorrect number or type of arguments";\n'); | 849 body.Emit(' throw "Incorrect number or type of arguments";\n'); |
| 850 | 850 |
| 851 def GenerateDispatch(self, emitter, info, indent, position, overloads): | 851 def CombineOverloads(self, overloads): |
|
Anton Muhin
2012/05/23 14:43:33
what about the following implementation:
out = [o
| |
| 852 # Combine overloads that can be implemented by the same native method. This | |
| 853 # undoes the expansion of optional arguments into multiple overloads unless | |
| 854 # IDL merging has made the overloads necessary. Starting with overload with | |
| 855 # no optional arguments and grow it by adding optional arguments, then the | |
| 856 # longest overload can serve for all the shorter ones. | |
| 857 out = [] | |
| 858 seed_index = 0 | |
| 859 while seed_index < len(overloads): | |
| 860 seed = overloads[seed_index] | |
| 861 if len(seed.arguments) > 0 and seed.arguments[-1].is_optional: | |
| 862 # Must start with no optional arguments. | |
| 863 out.append(seed) | |
| 864 seed_index += 1 | |
| 865 continue | |
| 866 | |
| 867 prev = seed | |
| 868 probe_index = seed_index + 1 | |
| 869 while probe_index < len(overloads): | |
| 870 probe = overloads[probe_index] | |
| 871 if len(probe.arguments) != len(prev.arguments) + 1: | |
| 872 break | |
| 873 if probe.arguments[:-1] != prev.arguments: | |
| 874 break | |
| 875 if not probe.arguments[-1].is_optional: | |
| 876 break | |
| 877 # See Issue 3177. This test against known implemented types is to | |
|
Anton Muhin
2012/05/23 14:43:33
I suspect we need some more amendments in bindings
| |
| 878 # prevent combining a possibly unimplemented type. Combining with an | |
| 879 # unimplemented type will cause all set of combined overloads to become | |
| 880 # 'unimplemented', even if no argument is passed to the the | |
| 881 # unimplemented parameter. | |
| 882 if DartType(probe.arguments[-1].type.id) not in [ | |
| 883 'String', 'int', 'num', 'double', 'bool', | |
| 884 'IDBKeyRange']: | |
| 885 break | |
| 886 probe_index += 1 | |
| 887 prev = probe | |
| 888 out.append(prev) | |
| 889 seed_index = probe_index | |
| 890 | |
| 891 return out | |
| 892 | |
| 893 def PrintOverloadsComment(self, emitter, info, indent, note, overloads): | |
| 894 emitter.Emit('$(INDENT)//$NOTE\n', INDENT=indent, NOTE=note) | |
| 895 for operation in overloads: | |
| 896 params = ', '.join([ | |
| 897 ('[Optional] ' if arg.is_optional else '') + DartType(arg.type.id) + ' ' | |
| 898 + arg.id for arg in operation.arguments]) | |
| 899 emitter.Emit('$(INDENT)// $NAME($PARAMS)\n', | |
| 900 INDENT=indent, | |
| 901 NAME=info.name, | |
| 902 PARAMS=params) | |
| 903 emitter.Emit('$(INDENT)//\n', INDENT=indent) | |
| 904 | |
| 905 def GenerateDispatch(self, emitter, info, indent, overloads): | |
| 852 """Generates a dispatch to one of the overloads. | 906 """Generates a dispatch to one of the overloads. |
| 853 | 907 |
| 854 Arguments: | 908 Arguments: |
| 855 emitter: an Emitter for the body of a block of code. | 909 emitter: an Emitter for the body of a block of code. |
| 856 info: the compound information about the operation and its overloads. | 910 info: the compound information about the operation and its overloads. |
| 857 indent: an indentation string for generated code. | 911 indent: an indentation string for generated code. |
| 858 position: the index of the parameter to dispatch on. | 912 position: the index of the parameter to dispatch on. |
| 859 overloads: a list of the remaining IDLOperations to dispatch. | 913 overloads: a list of the IDLOperations to dispatch. |
| 860 | 914 |
| 861 Returns True if the dispatch can fall through on failure, False if the code | 915 Returns True if the dispatch can fall through on failure, False if the code |
| 862 always dispatches. | 916 always dispatches. |
| 863 """ | 917 """ |
| 864 | 918 |
| 865 def NullCheck(name): | 919 def NullCheck(name): |
| 866 return '%s === null' % name | 920 return '%s === null' % name |
| 867 | 921 |
| 868 def TypeCheck(name, type): | 922 def TypeCheck(name, type): |
| 869 return '%s is %s' % (name, type) | 923 return '%s is %s' % (name, type) |
| 870 | 924 |
| 871 def ShouldGenerateSingleOperation(): | 925 def IsNullable(type): |
| 872 if position == len(info.param_infos): | 926 #return type != 'int' and type != 'num' |
| 873 if len(overloads) > 1: | 927 return True |
| 874 raise Exception('Duplicate operations ' + str(overloads)) | |
| 875 return True | |
| 876 | 928 |
| 877 # Check if we dispatch on RequiredCppParameter arguments. In this | 929 def PickRequiredCppSingleOperation(): |
| 878 # case all trailing arguments must be RequiredCppParameter and there | 930 # Returns a special case single operation, or None. Check if we dispatch |
| 879 # is no need in dispatch. | 931 # on RequiredCppParameter arguments. In this case all trailing arguments |
| 880 # TODO(antonm): better diagnositics. | 932 # must be RequiredCppParameter and there is no need in dispatch. |
| 881 if position >= len(overloads[0].arguments): | 933 def IsRequiredCppParameter(arg): |
| 882 def IsRequiredCppParameter(arg): | 934 return 'RequiredCppParameter' in arg.ext_attrs |
| 883 return 'RequiredCppParameter' in arg.ext_attrs | 935 def HasRequiredCppParameters(op): |
|
Anton Muhin
2012/05/23 14:43:33
first_required = itertools.dropwhile(lambda x: not
sra1
2012/05/25 01:40:05
This does not turn out so nice: unlike a list, the
| |
| 884 last_overload = overloads[-1] | 936 matches = filter(IsRequiredCppParameter, op.arguments) |
| 885 if (len(last_overload.arguments) > position and | 937 if matches: |
| 886 IsRequiredCppParameter(last_overload.arguments[position])): | 938 # Validate all the RequiredCppParameter ones are at the end. |
| 887 for overload in overloads: | 939 rematches = filter(IsRequiredCppParameter, |
| 888 args = overload.arguments[position:] | 940 op.arguments[len(op.arguments) - len(matches):]) |
| 889 if not all([IsRequiredCppParameter(arg) for arg in args]): | 941 if len(matches) != len(rematches): |
| 890 raise Exception('Invalid overload for RequiredCppParameter') | 942 raise Exception('Invalid RequiredCppParameter - all subsequent ' |
| 943 'parameters must also be RequiredCppParameter.') | |
| 891 return True | 944 return True |
| 945 return False | |
| 946 if any(HasRequiredCppParameters(op) for op in overloads): | |
|
Anton Muhin
2012/05/23 14:43:33
should it be any or longest?
sra1
2012/05/25 01:40:05
any, in case we have two unrelated overloads.
| |
| 947 longest = max(overloads, key=lambda op: len(op.arguments)) | |
| 948 # Validate all other overloads are prefixes. | |
| 949 for op in overloads: | |
| 950 for (index, arg) in enumerate(op.arguments): | |
|
Anton Muhin
2012/05/23 14:43:33
for (index, (arg1, arg2)) in enumerate(zip(op.argu
sra1
2012/05/25 01:40:05
Does not really shorten it since we still have to
| |
| 951 type1 = arg.type.id | |
| 952 type2 = longest.arguments[index].type.id | |
| 953 if type1 != type2: | |
| 954 raise Exception('Overloads with RequiredCppParameter have ' | |
| 955 'inconsistent types %s and %s for parameter #%s' % | |
| 956 (type1, type2, index)) | |
| 957 return longest | |
| 958 return None | |
| 892 | 959 |
| 960 single_operation = PickRequiredCppSingleOperation() | |
| 961 if single_operation: | |
| 962 self.GenerateSingleOperation(emitter, info, indent, single_operation) | |
| 893 return False | 963 return False |
| 894 | 964 |
| 895 if ShouldGenerateSingleOperation(): | 965 # Print just the interesting sets of overloads. |
| 896 self.GenerateSingleOperation(emitter, info, indent, overloads[-1]) | 966 if len(overloads) > 1 or len(info.overloads) > 1: |
| 897 return False | 967 self.PrintOverloadsComment(emitter, info, indent, '', info.overloads) |
| 968 if overloads != info.overloads: | |
| 969 self.PrintOverloadsComment(emitter, info, indent, ' -- reduced:', | |
| 970 overloads) | |
| 898 | 971 |
| 899 # FIXME: Consider a simpler dispatch that iterates over the | 972 # Match each operation in turn. |
| 900 # overloads and generates an overload specific check. Revisit | 973 # TODO: Optimize the dispatch to avoid repeated tests. |
| 901 # when we move to named optional arguments. | 974 fallthrough = True |
| 902 | 975 for operation in overloads: |
| 903 # Partition the overloads to divide and conquer on the dispatch. | 976 tests = [] |
| 904 positive = [] | 977 for (position, param) in enumerate(info.param_infos): |
| 905 negative = [] | 978 if position < len(operation.arguments): |
|
Anton Muhin
2012/05/23 14:43:33
why special case last argument?
sra1
2012/05/25 01:40:05
This is the out-of-arguments check.
position == le
| |
| 906 first_overload = overloads[0] | 979 arg = operation.arguments[position] |
| 907 param = info.param_infos[position] | 980 dart_type = DartType(arg.type.id) |
| 908 | 981 if dart_type == param.dart_type: |
|
Anton Muhin
2012/05/23 14:43:33
what does this test check?
sra1
2012/05/25 01:40:05
It checks if a test is necessary. It catches the
| |
| 909 if position < len(first_overload.arguments): | 982 test = None |
| 910 # FIXME: This will not work if the second overload has a more | 983 else: |
| 911 # precise type than the first. E.g., | 984 test = TypeCheck(param.name, dart_type) |
| 912 # void foo(Node x); | 985 if IsNullable(dart_type) or arg.is_optional: |
| 913 # void foo(Element x); | 986 test = '(%s || %s)' % (NullCheck(param.name), test) |
| 914 type = DartType(first_overload.arguments[position].type.id) | 987 else: |
| 915 test = TypeCheck(param.name, type) | 988 test = NullCheck(param.name) |
| 916 pred = lambda op: len(op.arguments) > position and DartType(op.arguments[p osition].type.id) == type | 989 if test: |
| 917 else: | 990 tests.append(test) |
| 918 type = None | 991 if tests: |
| 919 test = NullCheck(param.name) | 992 cond = ' && '.join(tests) |
| 920 pred = lambda op: position >= len(op.arguments) | 993 if len(cond) + len(indent) + 7 > 80: |
| 921 | 994 cond = (' &&\n' + indent + ' ').join(tests) |
| 922 for overload in overloads: | 995 call = emitter.Emit( |
| 923 if pred(overload): | 996 '$(INDENT)if ($COND) {\n' |
| 924 positive.append(overload) | 997 '$!CALL' |
| 998 '$(INDENT)}\n', | |
| 999 COND=cond, | |
| 1000 INDENT=indent) | |
| 1001 self.GenerateSingleOperation(call, info, indent + ' ', operation) | |
| 925 else: | 1002 else: |
| 926 negative.append(overload) | 1003 self.GenerateSingleOperation(emitter, info, indent, operation) |
| 927 | 1004 fallthrough = False |
| 928 if positive and negative: | 1005 return fallthrough |
| 929 (true_code, false_code) = emitter.Emit( | |
| 930 '$(INDENT)if ($COND) {\n' | |
| 931 '$!TRUE' | |
| 932 '$(INDENT)} else {\n' | |
| 933 '$!FALSE' | |
| 934 '$(INDENT)}\n', | |
| 935 COND=test, INDENT=indent) | |
| 936 fallthrough1 = self.GenerateDispatch( | |
| 937 true_code, info, indent + ' ', position + 1, positive) | |
| 938 fallthrough2 = self.GenerateDispatch( | |
| 939 false_code, info, indent + ' ', position, negative) | |
| 940 return fallthrough1 or fallthrough2 | |
| 941 | |
| 942 if negative: | |
| 943 raise Exception('Internal error, must be all positive') | |
| 944 | |
| 945 # All overloads require the same test. Do we bother? | |
| 946 | |
| 947 # If the test is the same as the method's formal parameter then checked mode | |
| 948 # will have done the test already. (It could be null too but we ignore that | |
| 949 # case since all the overload behave the same and we don't know which types | |
| 950 # in the IDL are not nullable.) | |
| 951 if type == param.dart_type: | |
| 952 return self.GenerateDispatch( | |
| 953 emitter, info, indent, position + 1, positive) | |
| 954 | |
| 955 # Otherwise the overloads have the same type but the type is a subtype of | |
| 956 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
| 957 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
| 958 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
| 959 # that Y = Z-X, so we need to check for Y. | |
| 960 true_code = emitter.Emit( | |
| 961 '$(INDENT)if ($COND) {\n' | |
| 962 '$!TRUE' | |
| 963 '$(INDENT)}\n', | |
| 964 COND=test, INDENT=indent) | |
| 965 self.GenerateDispatch( | |
| 966 true_code, info, indent + ' ', position + 1, positive) | |
| 967 return True | |
| 968 | 1006 |
| 969 def AddOperation(self, info): | 1007 def AddOperation(self, info): |
| 970 self._AddOperation(info) | 1008 self._AddOperation(info) |
| 971 | 1009 |
| 972 def AddStaticOperation(self, info): | 1010 def AddStaticOperation(self, info): |
| 973 self._AddOperation(info) | 1011 self._AddOperation(info) |
| 974 | 1012 |
| 975 def AddSecondaryOperation(self, interface, info): | 1013 def AddSecondaryOperation(self, interface, info): |
| 976 self.AddOperation(info) | 1014 self.AddOperation(info) |
| 977 | 1015 |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1211 for parent in interface.parents: | 1249 for parent in interface.parents: |
| 1212 parent_name = parent.type.id | 1250 parent_name = parent.type.id |
| 1213 if not database.HasInterface(parent.type.id): | 1251 if not database.HasInterface(parent.type.id): |
| 1214 continue | 1252 continue |
| 1215 parent_interface = database.GetInterface(parent.type.id) | 1253 parent_interface = database.GetInterface(parent.type.id) |
| 1216 if callback(parent_interface): | 1254 if callback(parent_interface): |
| 1217 return parent_interface | 1255 return parent_interface |
| 1218 parent_interface = _FindParent(parent_interface, database, callback) | 1256 parent_interface = _FindParent(parent_interface, database, callback) |
| 1219 if parent_interface: | 1257 if parent_interface: |
| 1220 return parent_interface | 1258 return parent_interface |
| OLD | NEW |