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

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: 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 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
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
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