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

Unified Diff: sdk/lib/html/scripts/htmldartgenerator.py

Issue 11363130: Cleaning up dart:html generation after interface/implementation merge. Removing most of the interfa… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Incorporating review feedback, cleaning up comments Created 8 years, 1 month 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
« no previous file with comments | « sdk/lib/html/dartium/html_dartium.dart ('k') | sdk/lib/html/scripts/htmleventgenerator.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/html/scripts/htmldartgenerator.py
diff --git a/sdk/lib/html/scripts/htmldartgenerator.py b/sdk/lib/html/scripts/htmldartgenerator.py
index a199963ba72c5cd4febeca4549ec093c7f990f7f..0dd7ab7ae7f89b879efcbdf8226a3cd00e03f5e4 100644
--- a/sdk/lib/html/scripts/htmldartgenerator.py
+++ b/sdk/lib/html/scripts/htmldartgenerator.py
@@ -6,23 +6,170 @@
"""This module provides shared functionality for the system to generate
dart:html APIs from the IDL database."""
-from generator import DartDomNameOfAttribute
+from generator import AnalyzeOperation, ConstantOutputOrder, \
+ DartDomNameOfAttribute, FindMatchingAttribute, IsDartCollectionType, \
+ IsPureInterface
+
+# Types that are accessible cross-frame in a limited fashion.
+# In these cases, the base type (e.g., Window) provides restricted access
+# while the subtype (e.g., LocalWindow) provides full access to the
+# corresponding objects if there are from the same frame.
+_secure_base_types = {
+ 'LocalWindow': 'Window',
+ 'LocalLocation': 'Location',
+ 'LocalHistory': 'History',
+}
class HtmlDartGenerator(object):
def __init__(self, interface, options):
+ self._database = options.database
self._interface = interface
+ self._type_registry = options.type_registry
+ self._interface_type_info = self._type_registry.TypeInfo(self._interface.id)
+ self._renamer = options.renamer
def EmitAttributeDocumentation(self, attribute):
+ """ Emits the MDN dartdoc comment for an attribute.
+ """
dom_name = DartDomNameOfAttribute(attribute)
self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */',
DOMINTERFACE=attribute.doc_js_interface_name,
DOMNAME=dom_name)
def EmitOperationDocumentation(self, operation):
+ """ Emits the MDN dartdoc comment for an operation.
+ """
self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */',
DOMINTERFACE=operation.overloads[0].doc_js_interface_name,
DOMNAME=operation.name)
+ def EmitEventGetter(self, events_class_name):
+ self._members_emitter.Emit(
+ '\n /**'
+ '\n * @domName EventTarget.addEventListener, '
+ 'EventTarget.removeEventListener, EventTarget.dispatchEvent'
+ '\n */'
+ '\n $TYPE get on =>\n new $TYPE(this);\n',
+ TYPE=events_class_name)
+
+ def AddMembers(self, interface, declare_only=False):
+ for const in sorted(interface.constants, ConstantOutputOrder):
+ self.AddConstant(const)
+
+ for attr in sorted(interface.attributes, ConstantOutputOrder):
+ if attr.type.id != 'EventListener':
+ self.AddAttribute(attr, declare_only)
+
+ # The implementation should define an indexer if the interface directly
+ # extends List.
+ element_type = None
+ requires_indexer = False
+ if self._interface_type_info.list_item_type():
+ self.AddIndexer(self._interface_type_info.list_item_type())
+ else:
+ for parent in self._database.Hierarchy(self._interface):
+ if parent == self._interface:
+ continue
+ parent_type_info = self._type_registry.TypeInfo(parent.id)
+ if parent_type_info.list_item_type():
+ self.AmendIndexer(parent_type_info.list_item_type())
+ break
+
+ # Group overloaded operations by id.
+ operationsById = {}
+ for operation in interface.operations:
+ if operation.id not in operationsById:
+ operationsById[operation.id] = []
+ operationsById[operation.id].append(operation)
+
+ # Generate operations.
+ for id in sorted(operationsById.keys()):
+ operations = operationsById[id]
+ info = AnalyzeOperation(interface, operations)
+ self.AddOperation(info, declare_only)
+
+ def AddSecondaryMembers(self, interface):
+ # With multiple inheritance, attributes and operations of non-first
+ # interfaces need to be added. Sometimes the attribute or operation is
+ # defined in the current interface as well as a parent. In that case we
+ # avoid making a duplicate definition and pray that the signatures match.
+ secondary_parents = self._TransitiveSecondaryParents(interface)
+ for parent_interface in sorted(secondary_parents):
+ if isinstance(parent_interface, str):
+ continue
+ for attr in sorted(parent_interface.attributes, ConstantOutputOrder):
+ if not FindMatchingAttribute(interface, attr):
+ self.SecondaryContext(parent_interface)
+ self.AddAttribute(attr)
+
+ # Group overloaded operations by id.
+ operationsById = {}
+ for operation in parent_interface.operations:
+ if operation.id not in operationsById:
+ operationsById[operation.id] = []
+ operationsById[operation.id].append(operation)
+
+ # Generate operations.
+ for id in sorted(operationsById.keys()):
+ if not any(op.id == id for op in interface.operations):
+ operations = operationsById[id]
+ info = AnalyzeOperation(interface, operations)
+ self.SecondaryContext(parent_interface)
+ self.AddOperation(info)
+
+ def AddAttribute(self, attribute, declare_only=False):
+ """ Adds an attribute to the generated class.
+ Arguments:
+ attribute - The attribute which is to be added.
+ declare_only- True if the attribute should be declared as an abstract
+ member and not include invocation code.
+ """
+ dom_name = DartDomNameOfAttribute(attribute)
+ attr_name = self._renamer.RenameMember(
+ self._interface.id, attribute, dom_name, 'get:')
+ if not attr_name or self._IsPrivate(attr_name):
+ return
+
+ html_setter_name = self._renamer.RenameMember(
+ self._interface.id, attribute, dom_name, 'set:')
+ read_only = (attribute.is_read_only or 'Replaceable' in attribute.ext_attrs
+ or not html_setter_name)
+
+ # We don't yet handle inconsistent renames of the getter and setter yet.
+ assert(not html_setter_name or attr_name == html_setter_name)
+
+ if declare_only:
+ self.DeclareAttribute(attribute,
+ self.SecureOutputType(attribute.type.id), attr_name, read_only)
+ else:
+ self.EmitAttribute(attribute, attr_name, read_only)
+
+ def AddOperation(self, info, declare_only=False):
+ """ Adds an operation to the generated class.
+ Arguments:
+ info - The operation info of the operation to be added.
+ declare_only- True if the operation should be declared as an abstract
+ member and not include invocation code.
+ """
+ # FIXME: When we pass in operations[0] below, we're assuming all
+ # overloaded operations have the same security attributes. This
+ # is currently true, but we should consider filtering earlier or
+ # merging the relevant data into info itself.
+ method_name = self._renamer.RenameMember(self._interface.id,
+ info.operations[0],
+ info.name)
+ if not method_name:
+ if info.name == 'item':
+ # FIXME: item should be renamed to operator[], not removed.
+ self.EmitOperation(info, '_item')
+ return
+
+ if declare_only:
+ self.DeclareOperation(info,
+ self.SecureOutputType(info.type_name), method_name)
+ else:
+ self.EmitOperation(info, method_name)
+
def AdditionalImplementedInterfaces(self):
# TODO: Include all implemented interfaces, including other Lists.
implements = []
@@ -37,6 +184,13 @@ class HtmlDartGenerator(object):
def AddConstructors(self, constructors, factory_provider, class_name,
base_class):
+ """ Adds all of the constructors.
+ Arguments:
+ constructors - List of the constructors to be added.
+ factory_provider - Name of the factory provider for this class.
+ class_name - The name of this class.
+ base_class - The name of the base class which this extends.
+ """
for constructor_info in constructors:
self._AddConstructor(constructor_info, factory_provider)
@@ -55,7 +209,8 @@ class HtmlDartGenerator(object):
' factory $CTOR.fromList(List<$TYPE> list) =>\n'
' $FACTORY.create$(CTOR)_fromList(list);\n'
'\n'
- ' factory $CTOR.fromBuffer(ArrayBuffer buffer, [int byteOffset, int length]) => \n'
+ ' factory $CTOR.fromBuffer(ArrayBuffer buffer, '
+ '[int byteOffset, int length]) => \n'
' $FACTORY.create$(CTOR)_fromBuffer(buffer, byteOffset, length);\n',
CTOR=self._interface.id,
TYPE=self._DartType(typed_array_type),
@@ -65,8 +220,9 @@ class HtmlDartGenerator(object):
constructor_info.GenerateFactoryInvocation(
self._DartType, self._members_emitter, factory_provider)
- def DeclareAttribute(self, attribute, type_name, html_name, read_only):
- # Declares an attribute but does not include the code to invoke it.
+ def DeclareAttribute(self, attribute, type_name, attr_name, read_only):
+ """ Declares an attribute but does not include the code to invoke it.
+ """
self.EmitAttributeDocumentation(attribute)
if read_only:
template = '\n $TYPE get $NAME;\n'
@@ -74,15 +230,74 @@ class HtmlDartGenerator(object):
template = '\n $TYPE $NAME;\n'
self._members_emitter.Emit(template,
- NAME=html_name,
+ NAME=attr_name,
TYPE=type_name)
- def DeclareOperation(self, operation, type_name, html_name):
- # Declares an operation but does not include the code to invoke it.
+ def DeclareOperation(self, operation, return_type_name, method_name):
+ """ Declares an operation but does not include the code to invoke it.
+ Arguments:
+ operation - The operation to be declared.
+ return_type_name - The name of the return type.
+ method_name - The name of the method.
+ """
self.EmitOperationDocumentation(operation)
self._members_emitter.Emit(
'\n'
' $TYPE $NAME($PARAMS);\n',
- TYPE=type_name,
- NAME=html_name,
+ TYPE=return_type_name,
+ NAME=method_name,
PARAMS=operation.ParametersDeclaration(self._DartType))
+
+ def SecureOutputType(self, type_name, is_dart_type=False):
+ """ Converts the type name to the secure type name for return types.
+ """
+ if is_dart_type:
+ dart_name = type_name
+ else:
+ dart_name = self._DartType(type_name)
+ # We only need to secure Window. Only local History and Location are
+ # returned in generated code.
+ assert(dart_name != 'History' and dart_name != 'Location')
+ if dart_name == 'LocalWindow':
+ return _secure_base_types[dart_name]
+ return dart_name
+
+ def SecureBaseName(self, type_name):
+ if type_name in _secure_base_types:
+ return _secure_base_types[type_name]
+
+ def _TransitiveSecondaryParents(self, interface):
+ """Returns a list of all non-primary parents.
+
+ The list contains the interface objects for interfaces defined in the
+ database, and the name for undefined interfaces.
+ """
+ def walk(parents):
+ for parent in parents:
+ parent_name = parent.type.id
+ if parent_name == 'EventTarget':
+ # Currently EventTarget is implemented as a mixin, not a proper
+ # super interface---ignore its members.
+ continue
+ if IsDartCollectionType(parent_name):
+ result.append(parent_name)
+ continue
+ if self._database.HasInterface(parent_name):
+ parent_interface = self._database.GetInterface(parent_name)
+ result.append(parent_interface)
+ walk(parent_interface.parents)
+
+ result = []
+ if interface.parents:
+ parent = interface.parents[0]
+ if IsPureInterface(parent.type.id):
+ walk(interface.parents)
+ else:
+ walk(interface.parents[1:])
+ return result
+
+ def _DartType(self, type_name):
+ return self._type_registry.DartType(type_name)
+
+ def _IsPrivate(self, name):
+ return name.startswith('_')
« no previous file with comments | « sdk/lib/html/dartium/html_dartium.dart ('k') | sdk/lib/html/scripts/htmleventgenerator.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698