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

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

Issue 10827428: Dispatch with conversion hooks (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: table Created 8 years, 4 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
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 system to generate 6 """This module provides shared functionality for the system to generate
7 Dart:html APIs from the IDL database.""" 7 Dart:html APIs from the IDL database."""
8 8
9 import emitter 9 import emitter
10 10
(...skipping 880 matching lines...) Expand 10 before | Expand all | Expand 10 after
891 if self._interface.id != 'NodeList': 891 if self._interface.id != 'NodeList':
892 template_file = 'immutable_list_mixin.darttemplate' 892 template_file = 'immutable_list_mixin.darttemplate'
893 template = self._system._templates.Load(template_file) 893 template = self._system._templates.Load(template_file)
894 self._members_emitter.Emit(template, E=self._DartType(element_type)) 894 self._members_emitter.Emit(template, E=self._DartType(element_type))
895 895
896 def AddAttribute(self, attribute, html_name, read_only): 896 def AddAttribute(self, attribute, html_name, read_only):
897 if self._HasCustomImplementation(attribute.id): 897 if self._HasCustomImplementation(attribute.id):
898 return 898 return
899 899
900 if attribute.id != html_name: 900 if attribute.id != html_name:
901 self._AddRenamingGetter(attribute, html_name) 901 self._AddAttributeUsingProperties(attribute, html_name, read_only)
902 if not read_only:
903 self._AddRenamingSetter(attribute, html_name)
904 return 902 return
905 903
906 # If the attribute is shadowing, we can't generate a shadowing 904 # If the attribute is shadowing, we can't generate a shadowing
907 # field (Issue 1633). 905 # field (Issue 1633).
906 # BUGBUG: _FindShadowedAttribute does not take into account the html
vsm 2012/08/22 18:49:36 s/BUGBUG/TODO(sra)/
907 # renaming. we should be looking for another attribute that has the same
908 # html_name. Two attributes with the same IDL name might not match if one
909 # is renamed.
908 (super_attribute, super_attribute_interface) = self._FindShadowedAttribute(a ttribute, _merged_html_interfaces) 910 (super_attribute, super_attribute_interface) = self._FindShadowedAttribute(a ttribute, _merged_html_interfaces)
909 if super_attribute: 911 if super_attribute:
910 if read_only: 912 if read_only:
911 if attribute.type.id == super_attribute.type.id: 913 if attribute.type.id == super_attribute.type.id:
912 # Compatible attribute, use the superclass property. This works 914 # Compatible attribute, use the superclass property. This works
913 # because JavaScript will do its own dynamic dispatch. 915 # because JavaScript will do its own dynamic dispatch.
914 self._members_emitter.Emit( 916 self._members_emitter.Emit(
915 '\n' 917 '\n'
916 ' // Use implementation from $SUPER.\n' 918 ' // Use implementation from $SUPER.\n'
917 ' // final $TYPE $NAME;\n', 919 ' // final $TYPE $NAME;\n',
918 SUPER=super_attribute_interface, 920 SUPER=super_attribute_interface,
919 NAME=DartDomNameOfAttribute(attribute), 921 NAME=DartDomNameOfAttribute(attribute),
920 TYPE=self._NarrowOutputType(attribute.type.id)) 922 TYPE=self._NarrowOutputType(attribute.type.id))
921 return 923 return
924 self._members_emitter.Emit('\n // Shadowing definition.')
925 self._AddAttributeUsingProperties(attribute, html_name, read_only)
926 return
922 927
923 self._members_emitter.Emit('\n // Shadowing definition.') 928 # If the type has a conversion
924 self._AddAttributeUsingProperties(attribute, read_only) 929 if (self._OutputConversion(attribute.type.id, attribute.id) or
930 self._InputConversion(attribute.type.id, attribute.id)):
931 self._AddAttributeUsingProperties(attribute, html_name, read_only)
925 return 932 return
926 933
927 output_type = self._NarrowOutputType(attribute.type.id) 934 output_type = self._NarrowOutputType(attribute.type.id)
928 input_type = self._NarrowInputType(attribute.type.id) 935 input_type = self._NarrowInputType(attribute.type.id)
929 if not read_only: 936 if not read_only:
930 self._members_emitter.Emit( 937 self._members_emitter.Emit(
931 '\n $TYPE $NAME;\n', 938 '\n $TYPE $NAME;\n',
932 NAME=DartDomNameOfAttribute(attribute), 939 NAME=DartDomNameOfAttribute(attribute),
933 TYPE=output_type) 940 TYPE=output_type)
934 else: 941 else:
935 self._members_emitter.Emit( 942 self._members_emitter.Emit(
936 '\n final $TYPE $NAME;\n', 943 '\n final $TYPE $NAME;\n',
937 NAME=DartDomNameOfAttribute(attribute), 944 NAME=DartDomNameOfAttribute(attribute),
938 TYPE=output_type) 945 TYPE=output_type)
939 946
940 def _AddAttributeUsingProperties(self, attribute, read_only): 947 def _AddAttributeUsingProperties(self, attribute, html_name, read_only):
941 self._AddGetter(attribute) 948 self._AddRenamingGetter(attribute, html_name)
942 if not read_only: 949 if not read_only:
943 self._AddSetter(attribute) 950 self._AddRenamingSetter(attribute, html_name)
944
945 def _AddGetter(self, attr):
946 self._AddRenamingGetter(attr, DartDomNameOfAttribute(attr))
947
948 def _AddSetter(self, attr):
949 self._AddRenamingSetter(attr, DartDomNameOfAttribute(attr))
950 951
951 def _AddRenamingGetter(self, attr, html_name): 952 def _AddRenamingGetter(self, attr, html_name):
953 conversion = self._OutputConversion(attr.type.id, attr.id)
954 if conversion:
955 return self._AddConvertingGetter(attr, html_name, conversion)
952 return_type = self._NarrowOutputType(attr.type.id) 956 return_type = self._NarrowOutputType(attr.type.id)
953 self._members_emitter.Emit( 957 self._members_emitter.Emit(
954 '\n $TYPE get $(HTML_NAME)() native "return this.$NAME;";\n', 958 '\n $TYPE get $HTML_NAME() native "return this.$NAME;";\n',
955 HTML_NAME=html_name, 959 HTML_NAME=html_name,
956 NAME=attr.id, 960 NAME=attr.id,
957 TYPE=return_type) 961 TYPE=return_type)
958 962
959 def _AddRenamingSetter(self, attr, html_name): 963 def _AddRenamingSetter(self, attr, html_name):
964 conversion = self._InputConversion(attr.type.id, attr.id)
965 if conversion:
966 return self._AddConvertingSetter(attr, html_name, conversion)
960 self._members_emitter.Emit( 967 self._members_emitter.Emit(
961 '\n void set $HTML_NAME($TYPE value)' 968 '\n void set $HTML_NAME($TYPE value)'
962 ' native "this.$NAME = value;";\n', 969 ' native "this.$NAME = value;";\n',
963 HTML_NAME=html_name, 970 HTML_NAME=html_name,
964 NAME=attr.id, 971 NAME=attr.id,
965 TYPE=self._NarrowInputType(attr.type.id)) 972 TYPE=self._NarrowInputType(attr.type.id))
966 973
974 def _AddConvertingGetter(self, attr, html_name, conversion):
975 #native_type = self._NarrowOutputType(attr.type.id)
976 #return_type = conversion.output_type
vsm 2012/08/22 18:49:36 Delete commented code.
977 self._members_emitter.Emit(
978 '\n $RETURN_TYPE get $HTML_NAME() => $CONVERT(this._$(HTML_NAME));'
979 '\n $NATIVE_TYPE get _$HTML_NAME() native "return this.$NAME;";'
980 '\n',
981 CONVERT=conversion.function_name,
982 HTML_NAME=html_name,
983 NAME=attr.id,
984 RETURN_TYPE=conversion.output_type,
985 NATIVE_TYPE=conversion.input_type)
986
987 def _AddConvertingSetter(self, attr, html_name, conversion):
988 self._members_emitter.Emit(
989 '\n void set $HTML_NAME($INPUT_TYPE value) {'
990 ' this._$HTML_NAME = $CONVERT(value); }'
991 '\n void set _$HTML_NAME(/*$NATIVE_TYPE*/ value)'
992 ' native "this.$NAME = value;";'
993 '\n',
994 CONVERT=conversion.function_name,
995 HTML_NAME=html_name,
996 NAME=attr.id,
997 INPUT_TYPE=conversion.input_type,
998 NATIVE_TYPE=conversion.output_type)
999
1000
967 def AddOperation(self, info, html_name): 1001 def AddOperation(self, info, html_name):
968 """ 1002 """
969 Arguments: 1003 Arguments:
970 info: An OperationInfo object. 1004 info: An OperationInfo object.
971 """ 1005 """
972 if self._HasCustomImplementation(info.name): 1006 if self._HasCustomImplementation(info.name):
973 return 1007 return
974 1008
975 # FIXME: support static operations. 1009 # FIXME: support static operations.
976 if info.IsStatic(): 1010 if info.IsStatic():
977 return 1011 return
978 1012
1013 # Any conversions needed?
1014 if any(self._OperationRequiresConversions(op) for op in info.overloads):
1015 self._AddOperationWithConversions(info, html_name)
1016 else:
1017 self._AddDirectNativeOperation(info, html_name)
1018
1019 def _AddDirectNativeOperation(self, info, html_name):
979 # Do we need a native body? 1020 # Do we need a native body?
980 if html_name != info.declared_name: 1021 if html_name != info.declared_name:
981 return_type = self._NarrowOutputType(info.type_name) 1022 return_type = self._NarrowOutputType(info.type_name)
982 1023
983 operation_emitter = self._members_emitter.Emit('$!SCOPE', 1024 operation_emitter = self._members_emitter.Emit('$!SCOPE',
984 TYPE=return_type, 1025 TYPE=return_type,
985 HTML_NAME=html_name, 1026 HTML_NAME=html_name,
986 NAME=info.declared_name, 1027 NAME=info.declared_name,
987 PARAMS=info.ParametersImplementationDeclaration( 1028 PARAMS=info.ParametersImplementationDeclaration(
988 lambda type_name: self._NarrowInputType(type_name))) 1029 lambda type_name: self._NarrowInputType(type_name)))
989 1030
990 operation_emitter.Emit( 1031 operation_emitter.Emit(
991 '\n' 1032 '\n'
1033 #' // @native("$NAME")\n;'
992 ' $TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n') 1034 ' $TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n')
993 else: 1035 else:
994 self._members_emitter.Emit( 1036 self._members_emitter.Emit(
995 '\n' 1037 '\n'
996 ' $TYPE $NAME($PARAMS) native;\n', 1038 ' $TYPE $NAME($PARAMS) native;\n',
997 TYPE=self._NarrowOutputType(info.type_name), 1039 TYPE=self._NarrowOutputType(info.type_name),
998 NAME=info.name, 1040 NAME=info.name,
999 PARAMS=info.ParametersImplementationDeclaration( 1041 PARAMS=info.ParametersImplementationDeclaration(
1000 lambda type_name: self._NarrowInputType(type_name))) 1042 lambda type_name: self._NarrowInputType(type_name)))
1001 1043
1044 def _AddOperationWithConversions(self, info, html_name):
1045 # Assert all operations have same return type.
1046 assert len(set([op.type.id for op in info.operations])) == 1
1047 info = info.CopyAndWidenDefaultParameters()
1048 output_conversion = self._OutputConversion(info.type_name, info.declared_nam e)
vsm 2012/08/22 18:49:36 line length
1049 if output_conversion:
1050 return_type = output_conversion.output_type
1051 native_return_type = output_conversion.input_type
1052 else:
1053 return_type = self._NarrowInputType(info.type_name)
1054 native_return_type = return_type
1055
1056 def InputType(type_name):
1057 conversion = self._InputConversion(type_name, info.declared_name)
1058 if conversion:
1059 return conversion.input_type
1060 else:
1061 return self._NarrowInputType(type_name)
1062
1063 body = self._members_emitter.Emit(
1064 '\n'
1065 ' $TYPE $(HTML_NAME)($PARAMS) {\n'
1066 '$!BODY'
1067 ' }\n',
1068 TYPE=return_type,
1069 HTML_NAME=html_name,
1070 PARAMS=info.ParametersImplementationDeclaration(InputType, '_default'))
1071
1072 argument_names = [param_info.name for param_info in info.param_infos]
1073 operations = info.operations
1074 ## DISPATCH
1075
1076 method_version = [0]
1077 temp_version = [0]
1078
1079 def GenerateCall(operation, argument_count, checks):
1080 if checks:
1081 (stmts_emitter, call_emitter) = body.Emit(
1082 ' if ($CHECKS) {\n$!STMTS$!CALL }\n',
1083 INDENT=' ',
1084 CHECKS=' &&\n '.join(checks))
1085 else:
1086 (stmts_emitter, call_emitter) = body.Emit('$!A$!B', INDENT=' ');
1087
1088 method_version[0] += 1
1089 target = '_%s_%d' % (html_name, method_version[0])
1090 arguments = []
1091 target_parameters = []
1092 for position, arg in enumerate(operation.arguments[:argument_count]):
1093 conversion = self._InputConversion(arg.type.id, operation.id)
1094 param_name = operation.arguments[position].id
1095 if conversion:
1096 temp_version[0] += 1
1097 temp_name = '%s_%s' % (param_name, temp_version[0])
1098 temp_type = conversion.output_type
1099 param_type = temp_type
1100 stmts_emitter.Emit(
1101 '$(INDENT)$TYPE $NAME = $CONVERT($ARG);\n',
1102 TYPE=TypeOrVar(temp_type),
1103 NAME=temp_name,
1104 CONVERT=conversion.function_name,
1105 ARG=argument_names[position])
1106 arguments.append(temp_name)
1107 else:
1108 arguments.append(argument_names[position])
1109 param_type = self._NarrowInputType(DartType(arg.type.id))
1110 target_parameters.append(
1111 '%s%s' % (TypeOrNothing(param_type), param_name))
1112
1113 argument_list = ', '.join(arguments)
1114 call = '%s(%s)' % (target, argument_list)
1115
1116 if output_conversion:
1117 call = '%s(%s)' % (output_conversion.function_name, call)
1118
1119 if operation.type.id == 'void':
1120 call_emitter.Emit('$(INDENT)$CALL;\n$(INDENT)return;\n',
1121 CALL=call)
1122 else:
1123 call_emitter.Emit('$(INDENT)return $CALL;\n', CALL=call)
1124
1125 self._members_emitter.Emit(
1126 ' $TYPE $TARGET($PARAMS) native "$NATIVE";\n',
1127 TYPE=native_return_type,
1128 TARGET=target,
1129 PARAMS=', '.join(target_parameters),
1130 NATIVE=info.declared_name)
1131
1132 def GenerateChecksAndCall(operation, argument_count):
1133 checks = ['_default == %s' % name for name in argument_names]
1134 for i in range(0, argument_count):
1135 argument = operation.arguments[i]
1136 argument_name = argument_names[i]
1137 test_type = self._DartType(argument.type.id)
1138 if test_type in ['Dynamic', 'Object']:
1139 checks[i] = '_default != %s' % argument_name
1140 else:
1141 checks[i] = '(%s is %s || %s == null)' % (
1142 argument_name, self._DartType(argument.type.id), argument_name)
1143 GenerateCall(operation, argument_count, checks)
1144
1145 # TODO: Optimize the dispatch to avoid repeated checks.
1146 if len(operations) > 1:
1147 for operation in operations:
1148 for position, argument in enumerate(operation.arguments):
1149 if self._IsOptional(operation, argument):
1150 GenerateChecksAndCall(operation, position)
1151 GenerateChecksAndCall(operation, len(operation.arguments))
1152 body.Emit(' throw "Incorrect number or type of arguments";\n');
1153 else:
1154 operation = operations[0]
1155 argument_count = len(operation.arguments)
1156 for position, argument in list(enumerate(operation.arguments))[::-1]:
1157 if self._IsOptional(operation, argument):
1158 check = '_default != %s' % argument_names[position]
1159 # argument_count instead of position + 1 is used here to cover one
1160 # complicated case. Consider foo(x, [Optional] y, [Optional=DefaultIs NullString] z)
1161 # (as of now it's modelled after HTMLMediaElement.webkitAddKey).
1162 # y is optional in WebCore, while z is not.
1163 # In this case, if y !== _null, we'd like to emit foo(x, y, z) invocat ion, not
1164 # foo(x, y).
vsm 2012/08/22 18:49:36 line len in this comment block
1165 GenerateCall(operation, argument_count, [check])
1166 argument_count = position
1167 GenerateCall(operation, argument_count, [])
1168
1169
1170 return
1171
1172 def _IsOptional(self, operation, argument):
1173 return IsOptional(argument)
1174
1175
1176 def _OperationRequiresConversions(self, operation):
1177 return (self._OperationRequiresOutputConversion(operation) or
1178 self._OperationRequiresInputConversions(operation))
1179
1180 def _OperationRequiresOutputConversion(self, operation):
1181 return self._OutputConversion(operation.type.id, operation.id)
1182
1183 def _OperationRequiresInputConversions(self, operation):
1184 return any(self._InputConversion(arg.type.id, operation.id)
1185 for arg in operation.arguments)
1186
1187 def _OutputConversion(self, idl_type, member):
1188 return FindConversion(idl_type, 'get', self._interface.id, member)
1189
1190 def _InputConversion(self, idl_type, member):
1191 return FindConversion(idl_type, 'set', self._interface.id, member)
1192
1002 def _HasCustomImplementation(self, member_name): 1193 def _HasCustomImplementation(self, member_name):
1003 member_name = '%s.%s' % (self._html_interface_name, member_name) 1194 member_name = '%s.%s' % (self._html_interface_name, member_name)
1004 return member_name in _js_custom_members 1195 return member_name in _js_custom_members
1005 1196
1006 def _HasJavaScriptIndexingBehaviour(self): 1197 def _HasJavaScriptIndexingBehaviour(self):
1007 """Returns True if the native object has an indexer and length property.""" 1198 """Returns True if the native object has an indexer and length property."""
1008 (element_type, requires_indexer) = ListImplementationInfo( 1199 (element_type, requires_indexer) = ListImplementationInfo(
1009 self._interface, self._database) 1200 self._interface, self._database)
1010 if element_type and requires_indexer: return True 1201 if element_type and requires_indexer: return True
1011 return False 1202 return False
1012 1203
1013 # ------------------------------------------------------------------------------ 1204 # ------------------------------------------------------------------------------
1014 1205
1015 class HtmlDart2JSSystem(System): 1206 class HtmlDart2JSSystem(System):
1016 1207
1017 def __init__(self, options): 1208 def __init__(self, options):
1018 super(HtmlDart2JSSystem, self).__init__(options) 1209 super(HtmlDart2JSSystem, self).__init__(options)
1019 1210
1020 def ImplementationGenerator(self, interface): 1211 def ImplementationGenerator(self, interface):
1021 return HtmlDart2JSClassGenerator(self, interface) 1212 return HtmlDart2JSClassGenerator(self, interface)
1022 1213
1023 def GenerateLibraries(self, dart_files): 1214 def GenerateLibraries(self, dart_files):
1024 self._GenerateLibFile( 1215 self._GenerateLibFile(
1025 'html_dart2js.darttemplate', 1216 'html_dart2js.darttemplate',
1026 os.path.join(self._output_dir, 'html_dart2js.dart'), 1217 os.path.join(self._output_dir, 'html_dart2js.dart'),
1027 dart_files) 1218 dart_files)
1028 1219
1029 def Finish(self): 1220 def Finish(self):
1030 pass 1221 pass
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698