Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 |
| OLD | NEW |