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 overloads = self.CombineOverloads(info.overloads) |
| 844 fallthrough = self.GenerateDispatch(body, info, ' ', overloads) | |
| 848 if fallthrough: | 845 if fallthrough: |
| 849 body.Emit(' throw "Incorrect number or type of arguments";\n'); | 846 body.Emit(' throw "Incorrect number or type of arguments";\n'); |
| 850 | 847 |
| 851 def GenerateDispatch(self, emitter, info, indent, position, overloads): | 848 def CombineOverloads(self, overloads): |
|
Anton Muhin
2012/05/18 11:33:40
that still looks weird to me to recombine overload
sra1
2012/05/23 00:30:39
Think of it as an optimization. Without it, the g
| |
| 849 # Combine overloads that can be implemented by the same native method. This | |
| 850 # undoes the expansion of optional arguments into multiple overloads unless | |
| 851 # IDL merging has made the overloads necessary. Starting with overload with | |
| 852 # no optional arguments and grow it by adding optional arguments, then the | |
| 853 # longest overload can serve for all the shorter ones. | |
| 854 out = [] | |
| 855 seed_index = 0 | |
| 856 while seed_index < len(overloads): | |
| 857 seed = overloads[seed_index] | |
| 858 if len(seed.arguments) > 0 and seed.arguments[-1].is_optional: | |
| 859 # Must start with no optional arguments. | |
| 860 out.append(seed) | |
| 861 seed_index += 1 | |
| 862 continue | |
| 863 | |
| 864 prev = seed | |
| 865 probe_index = seed_index + 1 | |
| 866 while probe_index < len(overloads): | |
| 867 probe = overloads[probe_index] | |
| 868 if len(probe.arguments) != len(prev.arguments) + 1: | |
| 869 break | |
| 870 if probe.arguments[0:-1] != prev.arguments: | |
|
Anton Muhin
2012/05/18 11:33:40
nit: probe.arguments[:-1] should do too.
sra1
2012/05/23 00:30:39
Done.
| |
| 871 break | |
| 872 if not probe.arguments[-1].is_optional: | |
| 873 break | |
| 874 probe_index += 1 | |
| 875 prev = probe | |
| 876 out.append(prev) | |
| 877 seed_index = probe_index | |
| 878 | |
| 879 return out | |
| 880 | |
| 881 def PrintOverloadsComment(self, emitter, info, indent, note, overloads): | |
| 882 emitter.Emit('$(INDENT)//$NOTE\n', INDENT=indent, NOTE=note) | |
| 883 for operation in overloads: | |
| 884 params = ', '.join([ | |
| 885 ('[Optional] ' if arg.is_optional else '') + DartType(arg.type.id) + ' ' | |
| 886 + arg.id for arg in operation.arguments]) | |
| 887 emitter.Emit('$(INDENT)// $NAME($PARAMS)\n', | |
| 888 INDENT=indent, | |
| 889 NAME=info.name, | |
| 890 PARAMS=params) | |
| 891 emitter.Emit('$(INDENT)//\n', INDENT=indent) | |
| 892 | |
| 893 def GenerateDispatch(self, emitter, info, indent, overloads): | |
| 852 """Generates a dispatch to one of the overloads. | 894 """Generates a dispatch to one of the overloads. |
| 853 | 895 |
| 854 Arguments: | 896 Arguments: |
| 855 emitter: an Emitter for the body of a block of code. | 897 emitter: an Emitter for the body of a block of code. |
| 856 info: the compound information about the operation and its overloads. | 898 info: the compound information about the operation and its overloads. |
| 857 indent: an indentation string for generated code. | 899 indent: an indentation string for generated code. |
| 858 position: the index of the parameter to dispatch on. | 900 position: the index of the parameter to dispatch on. |
| 859 overloads: a list of the remaining IDLOperations to dispatch. | 901 overloads: a list of the IDLOperations to dispatch. |
| 860 | 902 |
| 861 Returns True if the dispatch can fall through on failure, False if the code | 903 Returns True if the dispatch can fall through on failure, False if the code |
| 862 always dispatches. | 904 always dispatches. |
| 863 """ | 905 """ |
| 864 | 906 |
| 865 def NullCheck(name): | 907 def NullCheck(name): |
| 866 return '%s === null' % name | 908 return '%s === null' % name |
| 867 | 909 |
| 868 def TypeCheck(name, type): | 910 def TypeCheck(name, type): |
| 869 return '%s is %s' % (name, type) | 911 return '%s is %s' % (name, type) |
| 870 | 912 |
| 913 def IsNullable(type): | |
| 914 #return type != 'int' and type != 'num' | |
| 915 return True | |
| 916 | |
| 871 def ShouldGenerateSingleOperation(): | 917 def ShouldGenerateSingleOperation(): |
| 872 if position == len(info.param_infos): | |
| 873 if len(overloads) > 1: | |
| 874 raise Exception('Duplicate operations ' + str(overloads)) | |
| 875 return True | |
| 876 | |
| 877 # Check if we dispatch on RequiredCppParameter arguments. In this | 918 # Check if we dispatch on RequiredCppParameter arguments. In this |
| 878 # case all trailing arguments must be RequiredCppParameter and there | 919 # case all trailing arguments must be RequiredCppParameter and there |
| 879 # is no need in dispatch. | 920 # is no need in dispatch. |
| 880 # TODO(antonm): better diagnositics. | 921 # TODO(antonm): better diagnositics. |
| 881 if position >= len(overloads[0].arguments): | 922 def IsRequiredCppParameter(arg): |
| 882 def IsRequiredCppParameter(arg): | 923 return 'RequiredCppParameter' in arg.ext_attrs |
| 883 return 'RequiredCppParameter' in arg.ext_attrs | 924 def HasRequiredCppParameters(op): |
| 884 last_overload = overloads[-1] | 925 matches = filter(IsRequiredCppParameter, op.arguments) |
|
Anton Muhin
2012/05/18 11:33:40
that is somewhat complicated to read, maybe use it
| |
| 885 if (len(last_overload.arguments) > position and | 926 if matches: |
| 886 IsRequiredCppParameter(last_overload.arguments[position])): | 927 # Validate all following arguments are RequiredCppParameter. |
| 887 for overload in overloads: | 928 rematches = filter(IsRequiredCppParameter, |
| 888 args = overload.arguments[position:] | 929 op.arguments[len(op.arguments) - len(matches):]) |
| 889 if not all([IsRequiredCppParameter(arg) for arg in args]): | 930 if len(matches) != len(rematches): |
| 890 raise Exception('Invalid overload for RequiredCppParameter') | 931 raise Exception('Invalid overload for RequiredCppParameter') |
| 891 return True | 932 return True |
| 892 | 933 else: |
| 893 return False | 934 return False |
| 935 return any(HasRequiredCppParameters(op) for op in overloads) | |
| 894 | 936 |
| 895 if ShouldGenerateSingleOperation(): | 937 if ShouldGenerateSingleOperation(): |
| 896 self.GenerateSingleOperation(emitter, info, indent, overloads[-1]) | 938 self.GenerateSingleOperation(emitter, info, indent, overloads[-1]) |
| 897 return False | 939 return False |
| 898 | 940 |
| 899 # FIXME: Consider a simpler dispatch that iterates over the | 941 # Print just the interesting sets of overloads. |
| 900 # overloads and generates an overload specific check. Revisit | 942 if len(overloads) > 1 or len(info.overloads) > 1: |
| 901 # when we move to named optional arguments. | 943 self.PrintOverloadsComment(emitter, info, indent, '', info.overloads) |
| 944 if overloads != info.overloads: | |
| 945 self.PrintOverloadsComment(emitter, info, indent, ' -- reduced:', | |
| 946 overloads) | |
| 902 | 947 |
| 903 # Partition the overloads to divide and conquer on the dispatch. | 948 # Match each operation in turn. |
| 904 positive = [] | 949 # TODO: Optimize the dispatch to avoid repeated tests. |
| 905 negative = [] | 950 fallthrough = True |
| 906 first_overload = overloads[0] | 951 for operation in overloads: |
| 907 param = info.param_infos[position] | 952 tests = [] |
| 908 | 953 for position in range(0, len(info.param_infos)): |
|
Anton Muhin
2012/05/18 11:33:40
nit: for (position, param) in enumerate(info.param
sra1
2012/05/23 00:30:39
Done.
| |
| 909 if position < len(first_overload.arguments): | 954 param = info.param_infos[position] |
| 910 # FIXME: This will not work if the second overload has a more | 955 if position < len(operation.arguments): |
| 911 # precise type than the first. E.g., | 956 arg = operation.arguments[position] |
| 912 # void foo(Node x); | 957 type = DartType(arg.type.id) |
|
Anton Muhin
2012/05/18 11:33:40
nit: dart_type instead of type?
sra1
2012/05/23 00:30:39
Done.
| |
| 913 # void foo(Element x); | 958 if type == param.dart_type: |
|
Anton Muhin
2012/05/18 11:33:40
this check looks somewhat hacky, maybe it should b
sra1
2012/05/23 00:30:39
Done.
| |
| 914 type = DartType(first_overload.arguments[position].type.id) | 959 test = None |
| 915 test = TypeCheck(param.name, type) | 960 else: |
| 916 pred = lambda op: len(op.arguments) > position and DartType(op.arguments[p osition].type.id) == type | 961 test = TypeCheck(param.name, type) |
| 917 else: | 962 if IsNullable(type) or arg.is_optional: |
| 918 type = None | 963 test = '(%s || %s)' % (NullCheck(param.name), test) |
| 919 test = NullCheck(param.name) | 964 else: |
| 920 pred = lambda op: position >= len(op.arguments) | 965 test = NullCheck(param.name) |
| 921 | 966 if test: |
| 922 for overload in overloads: | 967 tests.append(test) |
| 923 if pred(overload): | 968 if tests: |
| 924 positive.append(overload) | 969 cond = ' && '.join(tests) |
| 970 if len(cond) + len(indent) + 7 > 80: | |
|
Anton Muhin
2012/05/18 11:33:40
:)
| |
| 971 cond = (' &&\n' + indent + ' ').join(tests) | |
| 972 call = emitter.Emit( | |
| 973 '$(INDENT)if ($COND) {\n' | |
| 974 '$!CALL' | |
| 975 '$(INDENT)}\n', | |
| 976 COND=cond, | |
| 977 INDENT=indent) | |
| 978 self.GenerateSingleOperation(call, info, indent + ' ', operation) | |
| 925 else: | 979 else: |
| 926 negative.append(overload) | 980 self.GenerateSingleOperation(emitter, info, indent, operation) |
| 927 | 981 fallthrough = False |
| 928 if positive and negative: | 982 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 | 983 |
| 969 def AddOperation(self, info): | 984 def AddOperation(self, info): |
| 970 self._AddOperation(info) | 985 self._AddOperation(info) |
| 971 | 986 |
| 972 def AddStaticOperation(self, info): | 987 def AddStaticOperation(self, info): |
| 973 self._AddOperation(info) | 988 self._AddOperation(info) |
| 974 | 989 |
| 975 def AddSecondaryOperation(self, interface, info): | 990 def AddSecondaryOperation(self, interface, info): |
| 976 self.AddOperation(info) | 991 self.AddOperation(info) |
| 977 | 992 |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1211 for parent in interface.parents: | 1226 for parent in interface.parents: |
| 1212 parent_name = parent.type.id | 1227 parent_name = parent.type.id |
| 1213 if not database.HasInterface(parent.type.id): | 1228 if not database.HasInterface(parent.type.id): |
| 1214 continue | 1229 continue |
| 1215 parent_interface = database.GetInterface(parent.type.id) | 1230 parent_interface = database.GetInterface(parent.type.id) |
| 1216 if callback(parent_interface): | 1231 if callback(parent_interface): |
| 1217 return parent_interface | 1232 return parent_interface |
| 1218 parent_interface = _FindParent(parent_interface, database, callback) | 1233 parent_interface = _FindParent(parent_interface, database, callback) |
| 1219 if parent_interface: | 1234 if parent_interface: |
| 1220 return parent_interface | 1235 return parent_interface |
| OLD | NEW |