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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: lib/dom/scripts/systemhtml.py
diff --git a/lib/dom/scripts/systemhtml.py b/lib/dom/scripts/systemhtml.py
index e7764e004adfb633732a8853c212cc06e4144b20..8f7582d1eafe941c740e143973a5c8383e51eb28 100644
--- a/lib/dom/scripts/systemhtml.py
+++ b/lib/dom/scripts/systemhtml.py
@@ -898,13 +898,15 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator):
return
if attribute.id != html_name:
- self._AddRenamingGetter(attribute, html_name)
- if not read_only:
- self._AddRenamingSetter(attribute, html_name)
+ self._AddAttributeUsingProperties(attribute, html_name, read_only)
return
# If the attribute is shadowing, we can't generate a shadowing
# field (Issue 1633).
+ # BUGBUG: _FindShadowedAttribute does not take into account the html
vsm 2012/08/22 18:49:36 s/BUGBUG/TODO(sra)/
+ # renaming. we should be looking for another attribute that has the same
+ # html_name. Two attributes with the same IDL name might not match if one
+ # is renamed.
(super_attribute, super_attribute_interface) = self._FindShadowedAttribute(attribute, _merged_html_interfaces)
if super_attribute:
if read_only:
@@ -919,9 +921,14 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator):
NAME=DartDomNameOfAttribute(attribute),
TYPE=self._NarrowOutputType(attribute.type.id))
return
-
self._members_emitter.Emit('\n // Shadowing definition.')
- self._AddAttributeUsingProperties(attribute, read_only)
+ self._AddAttributeUsingProperties(attribute, html_name, read_only)
+ return
+
+ # If the type has a conversion
+ if (self._OutputConversion(attribute.type.id, attribute.id) or
+ self._InputConversion(attribute.type.id, attribute.id)):
+ self._AddAttributeUsingProperties(attribute, html_name, read_only)
return
output_type = self._NarrowOutputType(attribute.type.id)
@@ -937,26 +944,26 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator):
NAME=DartDomNameOfAttribute(attribute),
TYPE=output_type)
- def _AddAttributeUsingProperties(self, attribute, read_only):
- self._AddGetter(attribute)
+ def _AddAttributeUsingProperties(self, attribute, html_name, read_only):
+ self._AddRenamingGetter(attribute, html_name)
if not read_only:
- self._AddSetter(attribute)
-
- def _AddGetter(self, attr):
- self._AddRenamingGetter(attr, DartDomNameOfAttribute(attr))
-
- def _AddSetter(self, attr):
- self._AddRenamingSetter(attr, DartDomNameOfAttribute(attr))
+ self._AddRenamingSetter(attribute, html_name)
def _AddRenamingGetter(self, attr, html_name):
+ conversion = self._OutputConversion(attr.type.id, attr.id)
+ if conversion:
+ return self._AddConvertingGetter(attr, html_name, conversion)
return_type = self._NarrowOutputType(attr.type.id)
self._members_emitter.Emit(
- '\n $TYPE get $(HTML_NAME)() native "return this.$NAME;";\n',
+ '\n $TYPE get $HTML_NAME() native "return this.$NAME;";\n',
HTML_NAME=html_name,
NAME=attr.id,
TYPE=return_type)
def _AddRenamingSetter(self, attr, html_name):
+ conversion = self._InputConversion(attr.type.id, attr.id)
+ if conversion:
+ return self._AddConvertingSetter(attr, html_name, conversion)
self._members_emitter.Emit(
'\n void set $HTML_NAME($TYPE value)'
' native "this.$NAME = value;";\n',
@@ -964,6 +971,33 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator):
NAME=attr.id,
TYPE=self._NarrowInputType(attr.type.id))
+ def _AddConvertingGetter(self, attr, html_name, conversion):
+ #native_type = self._NarrowOutputType(attr.type.id)
+ #return_type = conversion.output_type
vsm 2012/08/22 18:49:36 Delete commented code.
+ self._members_emitter.Emit(
+ '\n $RETURN_TYPE get $HTML_NAME() => $CONVERT(this._$(HTML_NAME));'
+ '\n $NATIVE_TYPE get _$HTML_NAME() native "return this.$NAME;";'
+ '\n',
+ CONVERT=conversion.function_name,
+ HTML_NAME=html_name,
+ NAME=attr.id,
+ RETURN_TYPE=conversion.output_type,
+ NATIVE_TYPE=conversion.input_type)
+
+ def _AddConvertingSetter(self, attr, html_name, conversion):
+ self._members_emitter.Emit(
+ '\n void set $HTML_NAME($INPUT_TYPE value) {'
+ ' this._$HTML_NAME = $CONVERT(value); }'
+ '\n void set _$HTML_NAME(/*$NATIVE_TYPE*/ value)'
+ ' native "this.$NAME = value;";'
+ '\n',
+ CONVERT=conversion.function_name,
+ HTML_NAME=html_name,
+ NAME=attr.id,
+ INPUT_TYPE=conversion.input_type,
+ NATIVE_TYPE=conversion.output_type)
+
+
def AddOperation(self, info, html_name):
"""
Arguments:
@@ -976,6 +1010,13 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator):
if info.IsStatic():
return
+ # Any conversions needed?
+ if any(self._OperationRequiresConversions(op) for op in info.overloads):
+ self._AddOperationWithConversions(info, html_name)
+ else:
+ self._AddDirectNativeOperation(info, html_name)
+
+ def _AddDirectNativeOperation(self, info, html_name):
# Do we need a native body?
if html_name != info.declared_name:
return_type = self._NarrowOutputType(info.type_name)
@@ -989,6 +1030,7 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator):
operation_emitter.Emit(
'\n'
+ #' // @native("$NAME")\n;'
' $TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n')
else:
self._members_emitter.Emit(
@@ -999,6 +1041,155 @@ class HtmlDart2JSClassGenerator(Dart2JSInterfaceGenerator):
PARAMS=info.ParametersImplementationDeclaration(
lambda type_name: self._NarrowInputType(type_name)))
+ def _AddOperationWithConversions(self, info, html_name):
+ # Assert all operations have same return type.
+ assert len(set([op.type.id for op in info.operations])) == 1
+ info = info.CopyAndWidenDefaultParameters()
+ output_conversion = self._OutputConversion(info.type_name, info.declared_name)
vsm 2012/08/22 18:49:36 line length
+ if output_conversion:
+ return_type = output_conversion.output_type
+ native_return_type = output_conversion.input_type
+ else:
+ return_type = self._NarrowInputType(info.type_name)
+ native_return_type = return_type
+
+ def InputType(type_name):
+ conversion = self._InputConversion(type_name, info.declared_name)
+ if conversion:
+ return conversion.input_type
+ else:
+ return self._NarrowInputType(type_name)
+
+ body = self._members_emitter.Emit(
+ '\n'
+ ' $TYPE $(HTML_NAME)($PARAMS) {\n'
+ '$!BODY'
+ ' }\n',
+ TYPE=return_type,
+ HTML_NAME=html_name,
+ PARAMS=info.ParametersImplementationDeclaration(InputType, '_default'))
+
+ argument_names = [param_info.name for param_info in info.param_infos]
+ operations = info.operations
+ ## DISPATCH
+
+ method_version = [0]
+ temp_version = [0]
+
+ def GenerateCall(operation, argument_count, checks):
+ if checks:
+ (stmts_emitter, call_emitter) = body.Emit(
+ ' if ($CHECKS) {\n$!STMTS$!CALL }\n',
+ INDENT=' ',
+ CHECKS=' &&\n '.join(checks))
+ else:
+ (stmts_emitter, call_emitter) = body.Emit('$!A$!B', INDENT=' ');
+
+ method_version[0] += 1
+ target = '_%s_%d' % (html_name, method_version[0])
+ arguments = []
+ target_parameters = []
+ for position, arg in enumerate(operation.arguments[:argument_count]):
+ conversion = self._InputConversion(arg.type.id, operation.id)
+ param_name = operation.arguments[position].id
+ if conversion:
+ temp_version[0] += 1
+ temp_name = '%s_%s' % (param_name, temp_version[0])
+ temp_type = conversion.output_type
+ param_type = temp_type
+ stmts_emitter.Emit(
+ '$(INDENT)$TYPE $NAME = $CONVERT($ARG);\n',
+ TYPE=TypeOrVar(temp_type),
+ NAME=temp_name,
+ CONVERT=conversion.function_name,
+ ARG=argument_names[position])
+ arguments.append(temp_name)
+ else:
+ arguments.append(argument_names[position])
+ param_type = self._NarrowInputType(DartType(arg.type.id))
+ target_parameters.append(
+ '%s%s' % (TypeOrNothing(param_type), param_name))
+
+ argument_list = ', '.join(arguments)
+ call = '%s(%s)' % (target, argument_list)
+
+ if output_conversion:
+ call = '%s(%s)' % (output_conversion.function_name, call)
+
+ if operation.type.id == 'void':
+ call_emitter.Emit('$(INDENT)$CALL;\n$(INDENT)return;\n',
+ CALL=call)
+ else:
+ call_emitter.Emit('$(INDENT)return $CALL;\n', CALL=call)
+
+ self._members_emitter.Emit(
+ ' $TYPE $TARGET($PARAMS) native "$NATIVE";\n',
+ TYPE=native_return_type,
+ TARGET=target,
+ PARAMS=', '.join(target_parameters),
+ NATIVE=info.declared_name)
+
+ def GenerateChecksAndCall(operation, argument_count):
+ checks = ['_default == %s' % name for name in argument_names]
+ for i in range(0, argument_count):
+ argument = operation.arguments[i]
+ argument_name = argument_names[i]
+ test_type = self._DartType(argument.type.id)
+ if test_type in ['Dynamic', 'Object']:
+ checks[i] = '_default != %s' % argument_name
+ else:
+ checks[i] = '(%s is %s || %s == null)' % (
+ argument_name, self._DartType(argument.type.id), argument_name)
+ GenerateCall(operation, argument_count, checks)
+
+ # TODO: Optimize the dispatch to avoid repeated checks.
+ if len(operations) > 1:
+ for operation in operations:
+ for position, argument in enumerate(operation.arguments):
+ if self._IsOptional(operation, argument):
+ GenerateChecksAndCall(operation, position)
+ GenerateChecksAndCall(operation, len(operation.arguments))
+ body.Emit(' throw "Incorrect number or type of arguments";\n');
+ else:
+ operation = operations[0]
+ argument_count = len(operation.arguments)
+ for position, argument in list(enumerate(operation.arguments))[::-1]:
+ if self._IsOptional(operation, argument):
+ check = '_default != %s' % argument_names[position]
+ # argument_count instead of position + 1 is used here to cover one
+ # complicated case. Consider foo(x, [Optional] y, [Optional=DefaultIsNullString] z)
+ # (as of now it's modelled after HTMLMediaElement.webkitAddKey).
+ # y is optional in WebCore, while z is not.
+ # In this case, if y !== _null, we'd like to emit foo(x, y, z) invocation, not
+ # foo(x, y).
vsm 2012/08/22 18:49:36 line len in this comment block
+ GenerateCall(operation, argument_count, [check])
+ argument_count = position
+ GenerateCall(operation, argument_count, [])
+
+
+ return
+
+ def _IsOptional(self, operation, argument):
+ return IsOptional(argument)
+
+
+ def _OperationRequiresConversions(self, operation):
+ return (self._OperationRequiresOutputConversion(operation) or
+ self._OperationRequiresInputConversions(operation))
+
+ def _OperationRequiresOutputConversion(self, operation):
+ return self._OutputConversion(operation.type.id, operation.id)
+
+ def _OperationRequiresInputConversions(self, operation):
+ return any(self._InputConversion(arg.type.id, operation.id)
+ for arg in operation.arguments)
+
+ def _OutputConversion(self, idl_type, member):
+ return FindConversion(idl_type, 'get', self._interface.id, member)
+
+ def _InputConversion(self, idl_type, member):
+ return FindConversion(idl_type, 'set', self._interface.id, member)
+
def _HasCustomImplementation(self, member_name):
member_name = '%s.%s' % (self._html_interface_name, member_name)
return member_name in _js_custom_members

Powered by Google App Engine
This is Rietveld 408576698