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

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 821 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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