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

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

Issue 10513004: Implement v8-like overload resolving. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: . Created 8 years, 6 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 | « lib/dom/scripts/generator.py ('k') | lib/html/dartium/html_dartium.dart » ('j') | 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 725 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 dart_declaration = 'void operator[]=(int index, %s value)' % element_type 736 dart_declaration = 'void operator[]=(int index, %s value)' % element_type
737 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration, 737 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration,
738 'Callback', True) 738 'Callback', True)
739 739
740 def _AddOperation(self, info): 740 def _AddOperation(self, info):
741 """ 741 """
742 Arguments: 742 Arguments:
743 info: An OperationInfo object. 743 info: An OperationInfo object.
744 """ 744 """
745 745
746 if 'CheckSecurityForNode' in info.overloads[0].ext_attrs: 746 operation = info.operations[0]
747
748 if 'CheckSecurityForNode' in operation.ext_attrs:
747 # FIXME: exclude from interface as well. 749 # FIXME: exclude from interface as well.
748 return 750 return
749 751
750 html_interface_name = self._HTMLInterfaceName(self._interface.id) 752 html_interface_name = self._HTMLInterfaceName(self._interface.id)
751 html_name = self._html_system.RenameInHtmlLibrary( 753 html_name = self._html_system.RenameInHtmlLibrary(
752 html_interface_name, info.name, implementation_class=True) 754 html_interface_name, info.name, implementation_class=True)
753 755
754 if not html_name and info.name == 'item': 756 if not html_name and info.name == 'item':
755 # FIXME: item should be renamed to operator[], not removed. 757 # FIXME: item should be renamed to operator[], not removed.
756 html_name = 'item' 758 html_name = 'item'
757 759
758 if not html_name: 760 if not html_name:
759 return 761 return
760 762
761 dart_declaration = '%s%s %s(%s)' % ( 763 dart_declaration = '%s%s %s(%s)' % (
762 'static ' if info.IsStatic() else '', 764 'static ' if info.IsStatic() else '',
763 self._DartType(info.type_name), 765 self._DartType(info.type_name),
764 html_name or info.name, 766 html_name,
765 info.ParametersImplementationDeclaration(self._DartType)) 767 info.ParametersImplementationDeclaration(self._DartType))
766 768
767 if 'Custom' in info.overloads[0].ext_attrs: 769 is_custom = 'Custom' in operation.ext_attrs
770 has_optional_arguments = any(IsOptional(argument) for argument in operation. arguments)
771 needs_dispatcher = not is_custom and (len(info.operations) > 1 or has_option al_arguments)
772 if not needs_dispatcher:
773 # Bind directly to native implementation
768 argument_count = (0 if info.IsStatic() else 1) + len(info.param_infos) 774 argument_count = (0 if info.IsStatic() else 1) + len(info.param_infos)
769 self._GenerateNativeBinding(info.name , argument_count, 775 cpp_callback_name = self._GenerateNativeBinding(
770 dart_declaration, 'Callback', True) 776 info.name, argument_count, dart_declaration, 'Callback', is_custom)
771 return 777 if not is_custom:
778 self._GenerateOperationNativeCallback(operation, operation.arguments, cp p_callback_name)
779 else:
780 self._GenerateDispatcher(info.operations, dart_declaration, [info.name for info in info.param_infos])
781
782 def _GenerateDispatcher(self, operations, dart_declaration, argument_names):
772 783
773 body = self._members_emitter.Emit( 784 body = self._members_emitter.Emit(
774 '\n' 785 '\n'
775 ' $DECLARATION {\n' 786 ' $DECLARATION {\n'
776 '$!BODY' 787 '$!BODY'
777 ' }\n', 788 ' }\n',
778 DECLARATION=dart_declaration) 789 DECLARATION=dart_declaration)
779 790
780 if self._interface.id == 'IDBObjectStore' and info.name == 'openCursor': 791 version = [1]
781 # FIXME: implement v8-like overload resolver and remove this hack. 792 def GenerateCall(operation, argument_count, checks):
782 info.overloads = info.overloads[1:] 793 if checks:
794 if operation.type.id != 'void':
795 template = ' if ($CHECKS) {\n return $CALL;\n }\n'
796 else:
797 template = ' if ($CHECKS) {\n $CALL;\n return;\n }\n'
798 else:
799 if operation.type.id != 'void':
800 template = ' return $CALL;\n'
801 else:
802 template = ' $CALL;\n'
783 803
784 self._native_version = 0 804 overload_name = '%s_%s' % (operation.id, version[0])
785 overloads = self.CombineOverloads(info.overloads) 805 version[0] += 1
786 fallthrough = self.GenerateDispatch(body, info, ' ', overloads) 806 argument_list = ', '.join(argument_names[:argument_count])
787 if fallthrough: 807 call = '_%s(%s)' % (overload_name, argument_list)
808 body.Emit(template, CHECKS=' && '.join(checks), CALL=call)
809
810 dart_declaration = '%s%s _%s(%s)' % (
811 'static ' if operation.is_static else '',
812 self._DartType(operation.type.id), overload_name, argument_list)
813 cpp_callback_name = self._GenerateNativeBinding(
814 overload_name, (0 if operation.is_static else 1) + argument_count,
815 dart_declaration, 'Callback', False)
816 self._GenerateOperationNativeCallback(operation, operation.arguments[:argu ment_count], cpp_callback_name)
817
818 def GenerateChecksAndCall(operation, argument_count):
819 checks = ['%s === null' % name for name in argument_names]
820 for i in range(0, argument_count):
821 argument = operation.arguments[i]
822 checks[i] = '%s is %s' % (argument_names[i], self._DartType(argument.typ e.id))
823 if IsOptional(argument) and 'Callback' in argument.ext_attrs:
824 checks[i] = '(%s or %s === null)' % (checks[position], argument_names[ i])
825 GenerateCall(operation, argument_count, checks)
826
827 def IsOptionalInWebCore(argument):
828 return IsOptional(argument) and not 'Callback' in argument.ext_attrs
829
830 # TODO: Optimize the dispatch to avoid repeated checks.
831 if len(operations) > 1:
832 for operation in operations:
833 for position, argument in enumerate(operation.arguments):
834 if IsOptionalInWebCore(argument):
835 GenerateChecksAndCall(operation, position)
836 GenerateChecksAndCall(operation, len(operation.arguments))
788 body.Emit(' throw "Incorrect number or type of arguments";\n'); 837 body.Emit(' throw "Incorrect number or type of arguments";\n');
789 838 else:
790 def CombineOverloads(self, overloads): 839 operation = operations[0]
791 # Combine overloads that can be implemented by the same native method. This 840 for position, argument in list(enumerate(operation.arguments))[::-1]:
792 # undoes the expansion of optional arguments into multiple overloads unless 841 if IsOptionalInWebCore(argument):
793 # IDL merging has made the overloads necessary. Starting with overload with 842 check = '%s === null' % argument_names[position]
794 # no optional arguments and grow it by adding optional arguments, then the 843 GenerateCall(operation, position, [check])
795 # longest overload can serve for all the shorter ones. 844 GenerateCall(operation, len(operation.arguments), [])
796 out = []
797 seed_index = 0
798 while seed_index < len(overloads):
799 seed = overloads[seed_index]
800 if len(seed.arguments) > 0 and IsOptional(seed.arguments[-1]):
801 # Must start with no optional arguments.
802 out.append(seed)
803 seed_index += 1
804 continue
805
806 prev = seed
807 probe_index = seed_index + 1
808 while probe_index < len(overloads):
809 probe = overloads[probe_index]
810 # Check that 'probe' extends 'prev' by one optional argument.
811 if len(probe.arguments) != len(prev.arguments) + 1:
812 break
813 if probe.arguments[:-1] != prev.arguments:
814 break
815 if not IsOptional(probe.arguments[-1]):
816 break
817 # See Issue 3177. This test against known implemented types is to
818 # prevent combining a possibly unimplemented type. Combining with an
819 # unimplemented type will cause all set of combined overloads to become
820 # 'unimplemented', even if no argument is passed to the the
821 # unimplemented parameter.
822 if DartType(probe.arguments[-1].type.id) not in [
823 'String', 'int', 'num', 'double', 'bool',
824 'IDBKeyRange']:
825 break
826 probe_index += 1
827 prev = probe
828 out.append(prev)
829 seed_index = probe_index
830
831 return out
832
833 def PrintOverloadsComment(self, emitter, info, indent, note, overloads):
834 emitter.Emit('$(INDENT)//$NOTE\n', INDENT=indent, NOTE=note)
835 for operation in overloads:
836 params = ', '.join([
837 ('[Optional] ' if IsOptional(arg) else '') + DartType(arg.type.id) + ' '
838 + arg.id for arg in operation.arguments])
839 emitter.Emit('$(INDENT)// $NAME($PARAMS)\n',
840 INDENT=indent,
841 NAME=info.name,
842 PARAMS=params)
843 emitter.Emit('$(INDENT)//\n', INDENT=indent)
844
845 def GenerateDispatch(self, emitter, info, indent, overloads):
846 """Generates a dispatch to one of the overloads.
847
848 Arguments:
849 emitter: an Emitter for the body of a block of code.
850 info: the compound information about the operation and its overloads.
851 indent: an indentation string for generated code.
852 position: the index of the parameter to dispatch on.
853 overloads: a list of the IDLOperations to dispatch.
854
855 Returns True if the dispatch can fall through on failure, False if the code
856 always dispatches.
857 """
858
859 def NullCheck(name):
860 return '%s === null' % name
861
862 def TypeCheck(name, type):
863 return '%s is %s' % (name, type)
864
865 def IsNullable(type):
866 #return type != 'int' and type != 'num'
867 return True
868
869 def PickRequiredCppSingleOperation():
870 # Returns a special case single operation, or None. Check if we dispatch
871 # on RequiredCppParameter arguments. In this case all trailing arguments
872 # must be RequiredCppParameter and there is no need in dispatch.
873 def IsRequiredCppParameter(arg):
874 return 'RequiredCppParameter' in arg.ext_attrs
875 def HasRequiredCppParameters(op):
876 matches = filter(IsRequiredCppParameter, op.arguments)
877 if matches:
878 # Validate all the RequiredCppParameter ones are at the end.
879 rematches = filter(IsRequiredCppParameter,
880 op.arguments[len(op.arguments) - len(matches):])
881 if len(matches) != len(rematches):
882 raise Exception('Invalid RequiredCppParameter - all subsequent '
883 'parameters must also be RequiredCppParameter.')
884 return True
885 return False
886 if any(HasRequiredCppParameters(op) for op in overloads):
887 longest = max(overloads, key=lambda op: len(op.arguments))
888 # Validate all other overloads are prefixes.
889 for op in overloads:
890 for (index, arg) in enumerate(op.arguments):
891 type1 = arg.type.id
892 type2 = longest.arguments[index].type.id
893 if type1 != type2:
894 raise Exception(
895 'Overloads for method %s with RequiredCppParameter have '
896 'inconsistent types %s and %s for parameter #%s' %
897 (info.name, type1, type2, index))
898 return longest
899 return None
900
901 single_operation = PickRequiredCppSingleOperation()
902 if single_operation:
903 self.GenerateSingleOperation(emitter, info, indent, single_operation)
904 return False
905
906 # Print just the interesting sets of overloads.
907 if len(overloads) > 1 or len(info.overloads) > 1:
908 self.PrintOverloadsComment(emitter, info, indent, '', info.overloads)
909 if overloads != info.overloads:
910 self.PrintOverloadsComment(emitter, info, indent, ' -- reduced:',
911 overloads)
912
913 # Match each operation in turn.
914 # TODO: Optimize the dispatch to avoid repeated tests.
915 fallthrough = True
916 for operation in overloads:
917 tests = []
918 for (position, param) in enumerate(info.param_infos):
919 if position < len(operation.arguments):
920 arg = operation.arguments[position]
921 dart_type = self._DartType(arg.type.id)
922 if dart_type == param.dart_type:
923 # The overload type matches the method parameter type exactly. We
924 # will have already tested this type in checked mode, and the target
925 # will expect (i.e. check) this type. This case happens when all
926 # the overloads have the same type in this position, including the
927 # trivial case of one overload.
928 test = None
929 else:
930 test = TypeCheck(param.name, dart_type)
931 if IsNullable(dart_type) or IsOptional(arg):
932 test = '(%s || %s)' % (NullCheck(param.name), test)
933 else:
934 test = NullCheck(param.name)
935 if test:
936 tests.append(test)
937 if tests:
938 cond = ' && '.join(tests)
939 if len(cond) + len(indent) + 7 > 80:
940 cond = (' &&\n' + indent + ' ').join(tests)
941 call = emitter.Emit(
942 '$(INDENT)if ($COND) {\n'
943 '$!CALL'
944 '$(INDENT)}\n',
945 COND=cond,
946 INDENT=indent)
947 self.GenerateSingleOperation(call, info, indent + ' ', operation)
948 else:
949 self.GenerateSingleOperation(emitter, info, indent, operation)
950 fallthrough = False
951 return fallthrough
952 845
953 def AddOperation(self, info): 846 def AddOperation(self, info):
954 self._AddOperation(info) 847 self._AddOperation(info)
955 848
956 def AddStaticOperation(self, info): 849 def AddStaticOperation(self, info):
957 self._AddOperation(info) 850 self._AddOperation(info)
958 851
959 def AddSecondaryOperation(self, interface, info): 852 def AddSecondaryOperation(self, interface, info):
960 self.AddOperation(info) 853 self.AddOperation(info)
961 854
962 def GenerateSingleOperation(self, dispatch_emitter, info, indent, operation): 855 def _GenerateOperationNativeCallback(self, operation, arguments, cpp_callback_ name):
963 """Generates a call to a single operation.
964
965 Arguments:
966 dispatch_emitter: an dispatch_emitter for the body of a block of code.
967 info: the compound information about the operation and its overloads.
968 indent: an indentation string for generated code.
969 operation: the IDLOperation to call.
970 """
971
972 self._native_version += 1
973 native_name = info.name
974 if self._native_version > 1:
975 native_name = '%s_%s' % (native_name, self._native_version)
976 argument_list = ', '.join([info.param_infos[i].name
977 for (i, arg) in enumerate(operation.arguments)])
978
979 # Generate dispatcher.
980 if info.type_name != 'void':
981 dispatch_emitter.Emit('$(INDENT)return _$NATIVENAME($ARGS);\n',
982 INDENT=indent,
983 NATIVENAME=native_name,
984 ARGS=argument_list)
985 else:
986 dispatch_emitter.Emit('$(INDENT)_$NATIVENAME($ARGS);\n'
987 '$(INDENT)return;\n',
988 INDENT=indent,
989 NATIVENAME=native_name,
990 ARGS=argument_list)
991 # Generate binding.
992 modifier = ''
993 if operation.is_static:
994 modifier = 'static '
995 dart_declaration = '%s%s _%s(%s)' % (modifier, self._DartType(info.type_name ), native_name,
996 argument_list)
997 is_custom = 'Custom' in operation.ext_attrs
998 cpp_callback_name = self._GenerateNativeBinding(
999 native_name, (0 if operation.is_static else 1) + len(operation.arguments ), dart_declaration, 'Callback',
1000 is_custom)
1001 if is_custom:
1002 return
1003
1004 # Generate callback.
1005 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i d) 856 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i d)
1006 857
1007 parameter_definitions_emitter = emitter.Emitter() 858 parameter_definitions_emitter = emitter.Emitter()
1008 arguments = [] 859 cpp_arguments = []
1009 raises_exceptions = self._GenerateCallWithHandling( 860 raises_exceptions = self._GenerateCallWithHandling(
1010 operation, parameter_definitions_emitter, arguments) 861 operation, parameter_definitions_emitter, cpp_arguments)
1011 raises_exceptions = raises_exceptions or len(operation.arguments) > 0 or ope ration.raises 862 raises_exceptions = raises_exceptions or len(arguments) > 0 or operation.rai ses
1012 863
1013 # Process Dart arguments. 864 # Process Dart cpp_arguments.
1014 start_index = 1 865 start_index = 1
1015 if operation.is_static: 866 if operation.is_static:
1016 start_index = 0 867 start_index = 0
1017 for (i, argument) in enumerate(operation.arguments): 868 for (i, argument) in enumerate(arguments):
1018 if (i == len(operation.arguments) - 1 and 869 if (i == len(arguments) - 1 and
1019 self._interface.id == 'Console' and 870 self._interface.id == 'Console' and
1020 argument.id == 'arg'): 871 argument.id == 'arg'):
1021 # FIXME: we are skipping last argument here because it was added in 872 # FIXME: we are skipping last argument here because it was added in
1022 # supplemental dart.idl. Cleanup dart.idl and remove this check. 873 # supplemental dart.idl. Cleanup dart.idl and remove this check.
1023 break 874 break
1024 argument_expression = self._GenerateToNative( 875 argument_expression = self._GenerateToNative(
1025 parameter_definitions_emitter, argument, start_index + i) 876 parameter_definitions_emitter, argument, start_index + i)
1026 arguments.append(argument_expression) 877 cpp_arguments.append(argument_expression)
1027 878
1028 if operation.id in ['addEventListener', 'removeEventListener']: 879 if operation.id in ['addEventListener', 'removeEventListener']:
1029 # addEventListener's and removeEventListener's last argument is marked 880 # addEventListener's and removeEventListener's last argument is marked
1030 # as optional in idl, but is not optional in webcore implementation. 881 # as optional in idl, but is not optional in webcore implementation.
1031 if len(operation.arguments) == 2: 882 if len(arguments) == 2:
1032 arguments.append('false') 883 cpp_arguments.append('false')
1033 884
1034 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope rty': 885 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope rty':
1035 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart 886 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart
1036 # idl, but is not optional in webcore implementation. 887 # idl, but is not optional in webcore implementation.
1037 if len(operation.arguments) == 2: 888 if len(arguments) == 2:
1038 arguments.append('String()') 889 cpp_arguments.append('String()')
1039 890
1040 if 'NeedsUserGestureCheck' in operation.ext_attrs: 891 if 'NeedsUserGestureCheck' in operation.ext_attrs:
1041 arguments.append('DartUtilities::processingUserGesture') 892 cpp_arguments.append('DartUtilities::processingUserGesture')
1042 893
1043 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi on_name, operation) 894 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi on_name, operation)
1044 invocation = self._GenerateWebCoreInvocation(function_expression, arguments, 895 invocation = self._GenerateWebCoreInvocation(function_expression, cpp_argume nts,
1045 operation.type.id, operation.ext_attrs, operation.raises) 896 operation.type.id, operation.ext_attrs, operation.raises)
1046 self._GenerateNativeCallback(cpp_callback_name, 897 self._GenerateNativeCallback(cpp_callback_name,
1047 parameter_definitions=parameter_definitions_emitter.Fragments(), 898 parameter_definitions=parameter_definitions_emitter.Fragments(),
1048 needs_receiver=not operation.is_static, invocation=invocation, 899 needs_receiver=not operation.is_static, invocation=invocation,
1049 raises_exceptions=raises_exceptions) 900 raises_exceptions=raises_exceptions)
1050 901
1051 def _GenerateNativeCallback(self, callback_name, parameter_definitions, 902 def _GenerateNativeCallback(self, callback_name, parameter_definitions,
1052 needs_receiver, invocation, raises_exceptions): 903 needs_receiver, invocation, raises_exceptions):
1053 904
1054 if needs_receiver: 905 if needs_receiver:
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 for parent in interface.parents: 1047 for parent in interface.parents:
1197 parent_name = parent.type.id 1048 parent_name = parent.type.id
1198 if not database.HasInterface(parent.type.id): 1049 if not database.HasInterface(parent.type.id):
1199 continue 1050 continue
1200 parent_interface = database.GetInterface(parent.type.id) 1051 parent_interface = database.GetInterface(parent.type.id)
1201 if callback(parent_interface): 1052 if callback(parent_interface):
1202 return parent_interface 1053 return parent_interface
1203 parent_interface = _FindParent(parent_interface, database, callback) 1054 parent_interface = _FindParent(parent_interface, database, callback)
1204 if parent_interface: 1055 if parent_interface:
1205 return parent_interface 1056 return parent_interface
OLDNEW
« no previous file with comments | « lib/dom/scripts/generator.py ('k') | lib/html/dartium/html_dartium.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698