Index: client/dom/scripts/dartgenerator.py |
=================================================================== |
--- client/dom/scripts/dartgenerator.py (revision 5796) |
+++ client/dom/scripts/dartgenerator.py (working copy) |
@@ -1,634 +0,0 @@ |
-#!/usr/bin/python |
-# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
-# for details. All rights reserved. Use of this source code is governed by a |
-# BSD-style license that can be found in the LICENSE file. |
- |
-"""This module generates Dart APIs from the IDL database.""" |
- |
-import emitter |
-import idlnode |
-import logging |
-import multiemitter |
-import os |
-import re |
-import shutil |
-from generator import * |
-from systembase import * |
-from systemfrog import * |
-from systemhtml import * |
-from systeminterface import * |
-from systemnative import * |
-from systemwrapping import * |
-from templateloader import TemplateLoader |
- |
-_logger = logging.getLogger('dartgenerator') |
- |
-def MergeNodes(node, other): |
- node.operations.extend(other.operations) |
- for attribute in other.attributes: |
- if not node.has_attribute(attribute): |
- node.attributes.append(attribute) |
- |
- node.constants.extend(other.constants) |
- |
-class DartGenerator(object): |
- """Utilities to generate Dart APIs and corresponding JavaScript.""" |
- |
- def __init__(self, auxiliary_dir, template_dir, base_package): |
- """Constructor for the DartGenerator. |
- |
- Args: |
- auxiliary_dir -- location of auxiliary handwritten classes |
- template_dir -- location of template files |
- base_package -- the base package name for the generated code. |
- """ |
- self._auxiliary_dir = auxiliary_dir |
- self._template_dir = template_dir |
- self._base_package = base_package |
- self._auxiliary_files = {} |
- self._dart_templates_re = re.compile(r'[\w.:]+<([\w\.<>:]+)>') |
- |
- self._emitters = None # set later |
- |
- |
- def _StripModules(self, type_name): |
- return type_name.split('::')[-1] |
- |
- def _IsCompoundType(self, database, type_name): |
- if IsPrimitiveType(type_name): |
- return True |
- |
- striped_type_name = self._StripModules(type_name) |
- if database.HasInterface(striped_type_name): |
- return True |
- |
- dart_template_match = self._dart_templates_re.match(type_name) |
- if dart_template_match: |
- # Dart templates |
- parent_type_name = type_name[0 : dart_template_match.start(1) - 1] |
- sub_type_name = dart_template_match.group(1) |
- return (self._IsCompoundType(database, parent_type_name) and |
- self._IsCompoundType(database, sub_type_name)) |
- return False |
- |
- def _IsDartType(self, type_name): |
- return '.' in type_name |
- |
- def LoadAuxiliary(self): |
- def Visitor(_, dirname, names): |
- for name in names: |
- if name.endswith('.dart'): |
- name = name[0:-5] # strip off ".dart" |
- self._auxiliary_files[name] = os.path.join(dirname, name) |
- os.path.walk(self._auxiliary_dir, Visitor, None) |
- |
- def RenameTypes(self, database, conversion_table, rename_javascript_binding_names): |
- """Renames interfaces using the given conversion table. |
- |
- References through all interfaces will be renamed as well. |
- |
- Args: |
- database: the database to apply the renames to. |
- conversion_table: maps old names to new names. |
- """ |
- |
- if conversion_table is None: |
- conversion_table = {} |
- |
- # Rename interfaces: |
- for old_name, new_name in conversion_table.items(): |
- if database.HasInterface(old_name): |
- _logger.info('renaming interface %s to %s' % (old_name, new_name)) |
- interface = database.GetInterface(old_name) |
- database.DeleteInterface(old_name) |
- if not database.HasInterface(new_name): |
- interface.id = new_name |
- database.AddInterface(interface) |
- else: |
- new_interface = database.GetInterface(new_name) |
- MergeNodes(new_interface, interface) |
- |
- interface.javascript_binding_name = (old_name if rename_javascript_binding_names |
- else new_name) |
- |
- # Fix references: |
- for interface in database.GetInterfaces(): |
- for idl_type in interface.all(idlnode.IDLType): |
- type_name = self._StripModules(idl_type.id) |
- if type_name in conversion_table: |
- idl_type.id = conversion_table[type_name] |
- |
- def FilterMembersWithUnidentifiedTypes(self, database): |
- """Removes unidentified types. |
- |
- Removes constants, attributes, operations and parents with unidentified |
- types. |
- """ |
- |
- for interface in database.GetInterfaces(): |
- def IsIdentified(idl_node): |
- node_name = idl_node.id if idl_node.id else 'parent' |
- for idl_type in idl_node.all(idlnode.IDLType): |
- type_name = idl_type.id |
- if (type_name is not None and |
- self._IsCompoundType(database, type_name)): |
- continue |
- _logger.warn('removing %s in %s which has unidentified type %s' % |
- (node_name, interface.id, type_name)) |
- return False |
- return True |
- |
- interface.constants = filter(IsIdentified, interface.constants) |
- interface.attributes = filter(IsIdentified, interface.attributes) |
- interface.operations = filter(IsIdentified, interface.operations) |
- interface.parents = filter(IsIdentified, interface.parents) |
- |
- def FilterInterfaces(self, database, |
- and_annotations=[], |
- or_annotations=[], |
- exclude_displaced=[], |
- exclude_suppressed=[]): |
- """Filters a database to remove interfaces and members that are missing |
- annotations. |
- |
- The FremontCut IDLs use annotations to specify implementation |
- status in various platforms. For example, if a member is annotated |
- with @WebKit, this means that the member is supported by WebKit. |
- |
- Args: |
- database -- the database to filter |
- all_annotations -- a list of annotation names a member has to |
- have or it will be filtered. |
- or_annotations -- if a member has one of these annotations, it |
- won't be filtered even if it is missing some of the |
- all_annotations. |
- exclude_displaced -- if a member has this annotation and it |
- is marked as displaced it will always be filtered. |
- exclude_suppressed -- if a member has this annotation and it |
- is marked as suppressed it will always be filtered. |
- """ |
- |
- # Filter interfaces and members whose annotations don't match. |
- for interface in database.GetInterfaces(): |
- def HasAnnotations(idl_node): |
- """Utility for determining if an IDLNode has all |
- the required annotations""" |
- for a in exclude_displaced: |
- if (a in idl_node.annotations |
- and 'via' in idl_node.annotations[a]): |
- return False |
- for a in exclude_suppressed: |
- if (a in idl_node.annotations |
- and 'suppressed' in idl_node.annotations[a]): |
- return False |
- for a in or_annotations: |
- if a in idl_node.annotations: |
- return True |
- if and_annotations == []: |
- return False |
- for a in and_annotations: |
- if a not in idl_node.annotations: |
- return False |
- return True |
- |
- if HasAnnotations(interface): |
- interface.constants = filter(HasAnnotations, interface.constants) |
- interface.attributes = filter(HasAnnotations, interface.attributes) |
- interface.operations = filter(HasAnnotations, interface.operations) |
- interface.parents = filter(HasAnnotations, interface.parents) |
- else: |
- database.DeleteInterface(interface.id) |
- |
- self.FilterMembersWithUnidentifiedTypes(database) |
- |
- |
- def Generate(self, database, output_dir, |
- module_source_preference=[], source_filter=None, |
- super_database=None, common_prefix=None, super_map={}, |
- html_map={}, lib_dir=None, systems=[]): |
- """Generates Dart and JS files for the loaded interfaces. |
- |
- Args: |
- database -- database containing interfaces to generate code for. |
- output_dir -- directory to write generated files to. |
- module_source_preference -- priority order list of source annotations to |
- use when choosing a module name, if none specified uses the module name |
- from the database. |
- source_filter -- if specified, only outputs interfaces that have one of |
- these source annotation and rewrites the names of superclasses not |
- marked with this source to use the common prefix. |
- super_database -- database containing super interfaces that the generated |
- interfaces should extend. |
- common_prefix -- prefix for the common library, if any. |
- lib_file_path -- filename for generated .lib file, None if not required. |
- lib_template -- template file in this directory for generated lib file. |
- """ |
- |
- self._emitters = multiemitter.MultiEmitter() |
- self._database = database |
- self._output_dir = output_dir |
- |
- self._ComputeInheritanceClosure() |
- |
- self._systems = [] |
- |
- # TODO(jmesserly): only create these if needed |
- if ('htmlfrog' in systems) or ('htmldartium' in systems): |
- html_interface_system = HtmlInterfacesSystem( |
- TemplateLoader(self._template_dir, ['html/interface', 'html', '']), |
- self._database, self._emitters, self._output_dir, self) |
- self._systems.append(html_interface_system) |
- else: |
- interface_system = InterfacesSystem( |
- TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), |
- self._database, self._emitters, self._output_dir) |
- self._systems.append(interface_system) |
- |
- if 'native' in systems: |
- native_system = NativeImplementationSystem( |
- TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), |
- self._database, self._emitters, self._auxiliary_dir, |
- self._output_dir) |
- |
- self._systems.append(native_system) |
- |
- if 'wrapping' in systems: |
- wrapping_system = WrappingImplementationSystem( |
- TemplateLoader(self._template_dir, ['dom/wrapping', 'dom', '']), |
- self._database, self._emitters, self._output_dir) |
- |
- # Makes interface files available for listing in the library for the |
- # wrapping implementation. |
- wrapping_system._interface_system = interface_system |
- self._systems.append(wrapping_system) |
- |
- if 'dummy' in systems: |
- dummy_system = DummyImplementationSystem( |
- TemplateLoader(self._template_dir, ['dom/dummy', 'dom', '']), |
- self._database, self._emitters, self._output_dir) |
- |
- # Makes interface files available for listing in the library for the |
- # dummy implementation. |
- dummy_system._interface_system = interface_system |
- self._systems.append(dummy_system) |
- |
- if 'frog' in systems: |
- frog_system = FrogSystem( |
- TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), |
- self._database, self._emitters, self._output_dir) |
- |
- frog_system._interface_system = interface_system |
- self._systems.append(frog_system) |
- |
- if 'htmlfrog' in systems: |
- html_system = HtmlFrogSystem( |
- TemplateLoader(self._template_dir, |
- ['html/frog', 'html/impl', 'html', ''], |
- {'DARTIUM': False, 'FROG': True}), |
- self._database, self._emitters, self._output_dir, self) |
- |
- html_system._interface_system = html_interface_system |
- self._systems.append(html_system) |
- |
- if 'htmldartium' in systems: |
- html_system = HtmlDartiumSystem( |
- TemplateLoader(self._template_dir, |
- ['html/dartium', 'html/impl', 'html', ''], |
- {'DARTIUM': True, 'FROG': False}), |
- self._database, self._emitters, self._output_dir, self) |
- |
- html_system._interface_system = html_interface_system |
- self._systems.append(html_system) |
- |
- # Collect interfaces |
- interfaces = [] |
- for interface in database.GetInterfaces(): |
- if not MatchSourceFilter(source_filter, interface): |
- # Skip this interface since it's not present in the required source |
- _logger.info('Omitting interface - %s' % interface.id) |
- continue |
- interfaces.append(interface) |
- |
- # TODO(sra): Use this list of exception names to generate information to |
- # tell Frog which exceptions can be passed from JS to Dart code. |
- exceptions = self._CollectExceptions(interfaces) |
- |
- # Render all interfaces into Dart and save them in files. |
- for interface in self._PreOrderInterfaces(interfaces): |
- |
- super_interface = None |
- super_name = interface.id |
- |
- if super_name in super_map: |
- super_name = super_map[super_name] |
- |
- if (super_database is not None and |
- super_database.HasInterface(super_name)): |
- super_interface = super_name |
- |
- interface_name = interface.id |
- auxiliary_file = self._auxiliary_files.get(interface_name) |
- if auxiliary_file is not None: |
- _logger.info('Skipping %s because %s exists' % ( |
- interface_name, auxiliary_file)) |
- continue |
- |
- info = RecognizeCallback(interface) |
- if info: |
- for system in self._systems: |
- system.ProcessCallback(interface, info) |
- else: |
- if 'Callback' in interface.ext_attrs: |
- _logger.info('Malformed callback: %s' % interface.id) |
- self._ProcessInterface(interface, super_interface, |
- source_filter, common_prefix) |
- |
- # Libraries |
- if lib_dir: |
- for system in self._systems: |
- system.GenerateLibraries(lib_dir) |
- |
- for system in self._systems: |
- system.Finish() |
- |
- |
- def _PreOrderInterfaces(self, interfaces): |
- """Returns the interfaces in pre-order, i.e. parents first.""" |
- seen = set() |
- ordered = [] |
- def visit(interface): |
- if interface.id in seen: |
- return |
- seen.add(interface.id) |
- for parent in interface.parents: |
- if IsDartCollectionType(parent.type.id): |
- continue |
- if self._database.HasInterface(parent.type.id): |
- parent_interface = self._database.GetInterface(parent.type.id) |
- visit(parent_interface) |
- ordered.append(interface) |
- |
- for interface in interfaces: |
- visit(interface) |
- return ordered |
- |
- |
- def _ProcessInterface(self, interface, super_interface_name, |
- source_filter, |
- common_prefix): |
- """.""" |
- _logger.info('Generating %s' % interface.id) |
- |
- generators = [system.InterfaceGenerator(interface, |
- common_prefix, |
- super_interface_name, |
- source_filter) |
- for system in self._systems] |
- generators = filter(None, generators) |
- |
- for generator in generators: |
- generator.StartInterface() |
- |
- for const in sorted(interface.constants, ConstantOutputOrder): |
- for generator in generators: |
- generator.AddConstant(const) |
- |
- attributes = [attr for attr in interface.attributes |
- if not self._IsEventAttribute(interface, attr)] |
- for (getter, setter) in _PairUpAttributes(attributes): |
- for generator in generators: |
- generator.AddAttribute(getter, setter) |
- |
- # The implementation should define an indexer if the interface directly |
- # extends List. |
- element_type = MaybeListElementType(interface) |
- if element_type: |
- for generator in generators: |
- generator.AddIndexer(element_type) |
- # 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) |
- for generator in generators: |
- generator.AddOperation(info) |
- |
- # 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. |
- |
- for parent_interface in self._TransitiveSecondaryParents(interface): |
- if isinstance(parent_interface, str): # IsDartCollectionType(parent_interface) |
- continue |
- attributes = [attr for attr in parent_interface.attributes |
- if not FindMatchingAttribute(interface, attr)] |
- for (getter, setter) in _PairUpAttributes(attributes): |
- for generator in generators: |
- generator.AddSecondaryAttribute(parent_interface, getter, setter) |
- |
- # 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) |
- for generator in generators: |
- generator.AddSecondaryOperation(parent_interface, info) |
- |
- for generator in generators: |
- generator.FinishInterface() |
- return |
- |
- def _IsEventAttribute(self, interface, attr): |
- # Remove EventListener attributes like 'onclick' when addEventListener |
- # is available. |
- return (attr.type.id == 'EventListener' and |
- 'EventTarget' in self._AllImplementedInterfaces(interface)) |
- |
- 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: |
- if IsDartCollectionType(parent.type.id): |
- result.append(parent.type.id) |
- continue |
- if self._database.HasInterface(parent.type.id): |
- parent_interface = self._database.GetInterface(parent.type.id) |
- result.append(parent_interface) |
- walk(parent_interface.parents) |
- |
- result = [] |
- walk(interface.parents[1:]) |
- return result; |
- |
- |
- def _CollectExceptions(self, interfaces): |
- """Returns the names of all exception classes raised.""" |
- exceptions = set() |
- for interface in interfaces: |
- for attribute in interface.attributes: |
- if attribute.get_raises: |
- exceptions.add(attribute.get_raises.id) |
- if attribute.set_raises: |
- exceptions.add(attribute.set_raises.id) |
- for operation in interface.operations: |
- if operation.raises: |
- exceptions.add(operation.raises.id) |
- return exceptions |
- |
- |
- def Flush(self): |
- """Write out all pending files.""" |
- _logger.info('Flush...') |
- self._emitters.Flush() |
- |
- |
- def _ComputeInheritanceClosure(self): |
- def Collect(interface, seen, collected): |
- name = interface.id |
- if '<' in name: |
- # TODO(sra): Handle parameterized types. |
- return |
- if not name in seen: |
- seen.add(name) |
- collected.append(name) |
- for parent in interface.parents: |
- # TODO(sra): Handle parameterized types. |
- if not '<' in parent.type.id: |
- if self._database.HasInterface(parent.type.id): |
- Collect(self._database.GetInterface(parent.type.id), |
- seen, collected) |
- |
- self._inheritance_closure = {} |
- for interface in self._database.GetInterfaces(): |
- seen = set() |
- collected = [] |
- Collect(interface, seen, collected) |
- self._inheritance_closure[interface.id] = collected |
- |
- def _AllImplementedInterfaces(self, interface): |
- """Returns a list of the names of all interfaces implemented by 'interface'. |
- List includes the name of 'interface'. |
- """ |
- return self._inheritance_closure[interface.id] |
- |
-def _PairUpAttributes(attributes): |
- """Returns a list of (getter, setter) pairs sorted by name. |
- |
- One element of the pair may be None. |
- """ |
- names = sorted(set(attr.id for attr in attributes)) |
- getters = {} |
- setters = {} |
- for attr in attributes: |
- if attr.is_fc_getter: |
- getters[attr.id] = attr |
- elif attr.is_fc_setter and 'Replaceable' not in attr.ext_attrs: |
- setters[attr.id] = attr |
- return [(getters.get(id), setters.get(id)) for id in names] |
- |
-# ------------------------------------------------------------------------------ |
- |
-class DummyImplementationSystem(System): |
- """Generates a dummy implementation for use by the editor analysis. |
- |
- All the code comes from hand-written library files. |
- """ |
- |
- def __init__(self, templates, database, emitters, output_dir): |
- super(DummyImplementationSystem, self).__init__( |
- templates, database, emitters, output_dir) |
- factory_providers_file = os.path.join(self._output_dir, 'src', 'dummy', |
- 'RegularFactoryProviders.dart') |
- self._factory_providers_emitter = self._emitters.FileEmitter( |
- factory_providers_file) |
- self._impl_file_paths = [factory_providers_file] |
- |
- def InterfaceGenerator(self, |
- interface, |
- common_prefix, |
- super_interface_name, |
- source_filter): |
- return DummyInterfaceGenerator(self, interface) |
- |
- def ProcessCallback(self, interface, info): |
- pass |
- |
- def GenerateLibraries(self, lib_dir): |
- # Library generated for implementation. |
- self._GenerateLibFile( |
- 'dom_dummy.darttemplate', |
- os.path.join(lib_dir, 'dom_dummy.dart'), |
- (self._interface_system._dart_interface_file_paths + |
- self._interface_system._dart_callback_file_paths + |
- self._impl_file_paths)) |
- |
- |
-# ------------------------------------------------------------------------------ |
- |
-class DummyInterfaceGenerator(object): |
- """Generates dummy implementation.""" |
- |
- def __init__(self, system, interface): |
- self._system = system |
- self._interface = interface |
- |
- def StartInterface(self): |
- # There is no implementation to match the interface, but there might be a |
- # factory constructor for the Dart interface. |
- constructor_info = AnalyzeConstructor(self._interface) |
- if constructor_info: |
- dart_interface_name = self._interface.id |
- self._EmitFactoryProvider(dart_interface_name, constructor_info) |
- |
- def _EmitFactoryProvider(self, interface_name, constructor_info): |
- factory_provider = '_' + interface_name + 'FactoryProvider' |
- self._system._factory_providers_emitter.Emit( |
- self._system._templates.Load('factoryprovider.darttemplate'), |
- FACTORYPROVIDER=factory_provider, |
- CONSTRUCTOR=interface_name, |
- PARAMETERS=constructor_info.ParametersImplementationDeclaration()) |
- |
- def FinishInterface(self): |
- pass |
- |
- def AddConstant(self, constant): |
- pass |
- |
- def AddAttribute(self, getter, setter): |
- pass |
- |
- def AddSecondaryAttribute(self, interface, getter, setter): |
- pass |
- |
- def AddSecondaryOperation(self, interface, info): |
- pass |
- |
- def AddIndexer(self, element_type): |
- pass |
- |
- def AddTypedArrayConstructors(self, element_type): |
- pass |
- |
- def AddOperation(self, info): |
- pass |
- |
- def AddEventAttributes(self, event_attrs): |
- pass |