Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(481)

Side by Side Diff: lib/dom/scripts/systemnative.py

Issue 10387170: New dispatch from dom into native code. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rebase Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698