mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 08:33:32 +00:00
55f81f2210
- Add `.style.yapf` with configuration to use Google style. - Run `yapf` on all `.py` files in this repo. - Manually fix one trailing space in a doc string. - Run `git cl format runtime` to satisfy presubmit. Change-Id: I7e6bd11e91f07926b9188362599af398551eed79 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/111600 Commit-Queue: Nate Bosch <nbosch@google.com> Reviewed-by: Alexander Thomas <athom@google.com>
286 lines
12 KiB
Python
Executable file
286 lines
12 KiB
Python
Executable file
#!/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 os
|
|
import re
|
|
import shutil
|
|
from generator import *
|
|
from idlnode import IDLType, IDLInterface, resolveTypedef
|
|
|
|
_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, logging_level=logging.WARNING):
|
|
self._auxiliary_files = {}
|
|
self._dart_templates_re = re.compile(r'[\w.:]+<([\w \.<>:]+)>')
|
|
_logger.setLevel(logging_level)
|
|
|
|
def _StripModules(self, type_name):
|
|
return type_name.split('::')[-1]
|
|
|
|
def _IsCompoundType(self, database, type_name):
|
|
if IsRegisteredType(type_name):
|
|
return True
|
|
|
|
# References a typedef - normally a union type.
|
|
if database.HasTypeDef(type_name):
|
|
return True
|
|
|
|
if type_name.endswith('?'):
|
|
return self._IsCompoundType(database, type_name[:-len('?')])
|
|
|
|
if type_name.endswith('[]'):
|
|
return self._IsCompoundType(database, type_name[:-len('[]')])
|
|
|
|
stripped_type_name = self._StripModules(type_name)
|
|
if (database.HasInterface(stripped_type_name) or
|
|
database.HasDictionary(stripped_type_name)):
|
|
return True
|
|
|
|
if database.HasEnum(stripped_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, auxiliary_dir):
|
|
|
|
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(auxiliary_dir, Visitor, None)
|
|
|
|
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
|
|
# Ignore constructor warnings.
|
|
if not (interface.id in [
|
|
'Window', 'WorkerContext', 'WorkerGlobalScope'
|
|
] and type_name.endswith('Constructor')):
|
|
_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, super_database, generate_interface):
|
|
self._database = database
|
|
|
|
# Collect interfaces
|
|
interfaces = []
|
|
for interface in database.GetInterfaces():
|
|
if not MatchSourceFilter(interface):
|
|
# Skip this interface since it's not present in the required source
|
|
_logger.info('Omitting interface - %s' % interface.id)
|
|
continue
|
|
interfaces.append(interface)
|
|
|
|
# All web_gl constants from WebGLRenderingContextBase, WebGL2RenderingContextBase, WebGLDrawBuffers are generated
|
|
# in a synthesized class WebGL. Those IDLConstants are in web_gl_constants.
|
|
web_gl_constants = []
|
|
|
|
# Render all interfaces into Dart and save them in files.
|
|
for interface in self._PreOrderInterfaces(interfaces):
|
|
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
|
|
|
|
_logger.info('Generating %s' % interface.id)
|
|
generate_interface(interface, gl_constants=web_gl_constants)
|
|
|
|
# Generate the WEB_GL constants
|
|
web_gl_constants_interface = IDLInterface(None, "WebGL")
|
|
web_gl_constants_interface.constants = web_gl_constants
|
|
self._database._all_interfaces['WebGL'] = web_gl_constants_interface
|
|
generate_interface(web_gl_constants_interface)
|
|
|
|
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 IsEventTarget(self, database, interface):
|
|
if interface.id == 'EventTarget':
|
|
return True
|
|
for parent in interface.parents:
|
|
parent_name = parent.type.id
|
|
if database.HasInterface(parent_name):
|
|
parent_interface = database.GetInterface(parent.type.id)
|
|
if self.IsEventTarget(database, parent_interface):
|
|
return True
|
|
return False
|
|
|
|
def FixEventTargets(self, database):
|
|
for interface in database.GetInterfaces():
|
|
if self.IsEventTarget(database, interface):
|
|
# Add as an attribute for easy querying in generation code.
|
|
interface.ext_attrs['EventTarget'] = None
|
|
elif 'EventTarget' in interface.ext_attrs:
|
|
# Create fake EventTarget parent interface for interfaces that have
|
|
# 'EventTarget' extended attribute.
|
|
ast = [('Annotation', [('Id', 'WebKit')]),
|
|
('InterfaceType', ('ScopedName', 'EventTarget'))]
|
|
interface.parents.append(idlnode.IDLParentInterface(ast))
|
|
|
|
def AddMissingArguments(self, database):
|
|
ARG = idlnode.IDLArgument([('Type', ('ScopedName', 'object')),
|
|
('Id', 'arg')])
|
|
for interface in database.GetInterfaces():
|
|
for operation in interface.operations:
|
|
call_with = operation.ext_attrs.get('CallWith', [])
|
|
if not (isinstance(call_with, list)):
|
|
call_with = [call_with]
|
|
constructor_with = operation.ext_attrs.get(
|
|
'ConstructorCallWith', [])
|
|
if not (isinstance(constructor_with, list)):
|
|
constructor_with = [constructor_with]
|
|
call_with = call_with + constructor_with
|
|
|
|
if 'ScriptArguments' in call_with:
|
|
operation.arguments.append(ARG)
|
|
|
|
def CleanupOperationArguments(self, database):
|
|
for interface in database.GetInterfaces():
|
|
for operation in interface.operations:
|
|
# TODO(terry): Hack to remove 3rd arguments in setInterval/setTimeout.
|
|
if ((operation.id == 'setInterval' or operation.id == 'setTimeout') and \
|
|
operation.arguments[0].type.id == 'any'):
|
|
operation.arguments.pop(2)
|
|
|
|
# Massage any operation argument type that is IDLEnum to String.
|
|
for index, argument in enumerate(operation.arguments):
|
|
type_name = argument.type.id
|
|
if database.HasEnum(type_name):
|
|
operation.arguments[index].type = IDLType('DOMString')
|