blob: f05f42813f0ddb971a8d810049f8bec60c60612e [file] [log] [blame]
#!/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 providesfunctionality for systems to generate
Elemental interfaces from the IDL database."""
import pdb
import os
import json
import systembaseelemental
from generator_java import *
class ElementalInterfacesSystem(systembaseelemental.SystemElemental):
def __init__(self, templates, database, emitters, output_dir):
super(ElementalInterfacesSystem, self).__init__(
templates, database, emitters, output_dir)
self._dart_interface_file_paths = []
def InterfaceGenerator(self,
interface,
common_prefix,
super_interface_name,
source_filter):
"""."""
module = getModule(interface.annotations)
if super_interface_name is not None:
interface_name = super_interface_name
else:
interface_name = interface.id
dart_interface_file_path = self._FilePathForElementalInterface(module, interface_name)
self._dart_interface_file_paths.append(dart_interface_file_path)
dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path)
template_file = 'java_interface_%s.darttemplate' % interface_name
template = self._templates.TryLoad(template_file)
if not template:
template = self._templates.Load('java_interface.darttemplate')
return ElementalInterfaceGenerator(module, self._database,
interface, dart_interface_code,
template,
common_prefix, super_interface_name,
source_filter)
def ProcessCallback(self, interface, info):
"""Generates a typedef for the callback interface."""
interface_name = interface.id
module = getModule(interface.annotations)
file_path = self._FilePathForElementalInterface(module, interface_name)
self._dart_callback_file_paths.append(file_path)
code = self._emitters.FileEmitter(file_path)
code.Emit(self._templates.Load('javacallback.darttemplate'),
ID=interface.id,
NAME=interface.id,
TYPE=info.type_name,
PARAMS=info.ParametersImplementationDeclaration(),
PACKAGE='elemental.%s' % module,
IMPORTS='',
CLASSJAVADOC='')
def GenerateLibraries(self, lib_dir):
pass
def _FilePathForElementalInterface(self, module, interface_name):
"""Returns the file path of the Dart interface definition."""
return os.path.join(self._output_dir, 'src', 'elemental', module,
'%s.java' % interface_name)
def _escapeComments(text):
return text.replace('*/', '*/').encode('utf-8')
# ------------------------------------------------------------------------------
class ElementalInterfaceGenerator(systembaseelemental.ElementalBase):
"""Generates Elemental Interface definition for one DOM IDL interface."""
def _GetJavaDoc(self, interface):
docid = interface.id
if docid not in self._docdatabase:
docid = 'HTML%s' % interface.id
if docid in self._docdatabase:
if 'summary' in self._docdatabase[docid]:
return _escapeComments(self._docdatabase[docid]['summary'])
return ""
def __init__(self, module, database, interface, emitter, template,
common_prefix, super_interface, source_filter):
"""Generates Dart code for the given interface.
Args:
interface -- an IDLInterface instance. It is assumed that all types have
been converted to Dart types (e.g. int, String), unless they are in the
same package as the interface.
common_prefix -- the prefix for the common library, if any.
super_interface -- the name of the common interface that this interface
implements, if any.
source_filter -- if specified, rewrites the names of any superinterfaces
that are not from these sources to use the common prefix.
"""
self._module = module
self._database = database
self._interface = interface
self._emitter = emitter
self._template = template
self._common_prefix = common_prefix
self._super_interface = super_interface
self._source_filter = source_filter
current_dir = os.path.dirname(__file__)
self._docdatabase = json.load(open(os.path.join(current_dir, '..', 'docs/database.json')))
def addImport(self, imports, typeid):
# skip primitive types that are all lowercase first letter
etype = DartType(typeid)
if '<' not in typeid and etype[0].isupper():
rawtype = etype.split('<')[0]
if rawtype in ['Indexable', 'Settable', 'Mappable']:
pmodule = 'util'
imports['import elemental.%s.%s;\n' % (pmodule, rawtype)]=1
elif etype not in java_lang and self._database.HasInterface(typeid):
pinterface = self._database.GetInterface(typeid)
pmodule = getModule(pinterface.annotations)
if pmodule != self._module:
imports['import elemental.%s.%s;\n' % (pmodule, rawtype)]=1
def StartInterface(self):
if self._super_interface:
typename = self._super_interface
else:
typename = self._interface.id
extends = []
suppressed_extends = []
imports = {}
implements_raw = {}
for attr in self._interface.attributes:
self.addImport(imports, attr.type.id)
for oper in self._interface.operations:
self.addImport(imports, oper.type.id)
for arg in oper.arguments:
self.addImport(imports, arg.type.id)
alreadyImplemented = {}
if len(self._interface.parents) > 0:
self.getImplements(alreadyImplemented, self._interface.parents[0])
for parent in self._interface.parents:
if not parent.type.id in alreadyImplemented or parent.type.id == 'ElementalMixinBase':
self.addImport(imports, parent.type.id)
# TODO(vsm): Remove source_filter.
rawtype = DartType(parent.type.id).split('<')[0]
if MatchSourceFilter(self._source_filter, parent) and DartType(parent.type.id) != 'Object' and rawtype not in implements_raw:
# Parent is a DOM type.
extends.append(DartType(parent.type.id))
implements_raw[rawtype]=1
#TODO(cromwellian) add in Indexable/IndexableInt/IndexableNumber
# elif '<' in parent.type.id:
# Parent is a Dart collection type.
# TODO(vsm): Make this check more robust.
# extends.append(parent.type.id)
# else:
# suppressed_extends.append('%s.%s' %
# (self._common_prefix, parent.type.id))
if self._interface.parents:
rawtype = DartType(self._interface.parents[0].type.id).split('<')[0]
if rawtype not in implements_raw:
extends.insert(0, DartType(self._interface.parents[0].type.id))
self.addImport(imports, self._interface.parents[0].type.id)
comment = ' extends'
extends_str = ''
if extends:
extends_str += ' extends ' + ', '.join(extends)
comment = ','
if suppressed_extends:
extends_str += ' /*%s %s */' % (comment, ', '.join(suppressed_extends))
factory_provider = None
constructor_info = AnalyzeConstructor(self._interface)
# TODO(vsm): Add appropriate package / namespace syntax.
(self._members_emitter,
self._top_level_emitter) = self._emitter.Emit(
self._template + '$!TOP_LEVEL',
ID=typename,
EXTENDS=extends_str, PACKAGE='elemental.' + self._module,
CLASSJAVADOC = self._GetJavaDoc(self._interface),
IMPORTS = ''.join(imports.keys()))
# TODO(cromwellian) auto-generate factory classes?
# if constructor_info:
# self._members_emitter.Emit(
# '\n'
# ' $CTOR($PARAMS);\n',
# CTOR=typename,
# PARAMS=constructor_info.ParametersInterfaceDeclaration());
# element_type = MaybeTypedArrayElementType(self._interface)
# if element_type:
# self._members_emitter.Emit(
# '\n'
# ' $CTOR(int length);\n'
# '\n'
# ' $CTOR.fromList(List<$TYPE> list);\n'
# '\n'
# ' $CTOR.fromBuffer(ArrayBuffer buffer,'
# ' [int byteOffset, int length]);\n',
# CTOR=self._interface.id,
# TYPE=DartType(element_type))
def FinishInterface(self):
# TODO(vsm): Use typedef if / when that is supported in Dart.
# Define variant as subtype.
if (self._super_interface and
self._interface.id is not self._super_interface):
consts_emitter = self._top_level_emitter.Emit(
'\n'
'interface $NAME extends $BASE {\n'
'$!CONSTS'
'}\n',
NAME=self._interface.id,
BASE=self._super_interface)
for const in sorted(self._interface.constants, ConstantOutputOrder):
self._EmitConstant(consts_emitter, const)
if self._interface.id == 'Document':
for iface in self._database.GetInterfaces():
if iface.id.endswith("Element"):
if iface.id == 'Element' or iface.id == 'SVGElement':
continue
callName = DartType(iface.id)
if iface.id == 'SVGSVGElement':
callName = 'SVGElement'
self._members_emitter.Emit('\n $TYPE create$CALL();\n',
CALL = callName,
TYPE=DartType(iface.id))
if self._interface.id == 'Window':
for iface in self._database.GetInterfaces():
element_type = MaybeTypedArrayElementType(iface)
if element_type:
self._members_emitter.Emit(
'\n'
' $TYPE new$CTOR(int length);\n'
'\n'
' $TYPE new$CTOR(IndexableNumber list);\n'
'\n'
' $TYPE new$CTOR(ArrayBuffer buffer,'
' int byteOffset, int length);\n',
CTOR=iface.id,
TYPE=iface.id)
constructor_info = AnalyzeConstructor(iface)
if constructor_info:
self._members_emitter.Emit(
'\n'
' $TYPE new$CTOR($PARAMS);\n',
TYPE=iface.id,
CTOR=iface.id,
PARAMS=constructor_info.ParametersInterfaceDeclaration());
def AddConstant(self, constant):
if (not self._super_interface or
self._interface.id is self._super_interface):
self._EmitConstant(self._members_emitter, constant)
def _EmitConstant(self, emitter, constant):
javadoc = self.find_doc(constant.id)
javadoctemplate = '\n /**\n * $JAVADOC\n */\n';
if javadoc == '':
javadoctemplate = ''
emitter.Emit('%s\n static final $TYPE$NAME = $VALUE;\n' % javadoctemplate,
NAME=constant.id,
TYPE=TypeOrNothing(DartType(constant.type.id),
None),
VALUE=constant.value,
JAVADOC = javadoc)
def AddAttribute(self, getter, setter, inheritedGetter, inheritedSetter):
javadoc = self.find_doc(getter.id)
javadoctemplate = '\n /**\n * $JAVADOC\n */\n';
if javadoc == '':
javadoctemplate = ''
if getter:
self._members_emitter.Emit('\n%s $TYPE $NAME();\n' % javadoctemplate,
NAME=getterName(getter),
TYPE=TypeOrVar(DartType(getter.type.id),
getter.type.id),
JAVADOC=javadoc)
if setter:
self._members_emitter.Emit('\n void $NAME($TYPE arg);\n',
NAME=setterName(setter),
TYPE=TypeOrVar(DartType(setter.type.id),
setter.type.id),
ARG=setter.type.id)
return
def AddIndexer(self, element_type):
# Interface inherits all operations from List<element_type>.
pass
def AddOperation(self, info, inherited):
"""
Arguments:
operations - contains the overloads, one or more operations with the same
name.
"""
javadoc = self.find_doc(info.name)
javadoctemplate = '\n /**\n * $JAVADOC\n */\n';
if javadoc == '':
javadoctemplate = ''
get_attrs = []
set_attrs = []
for attr in self._interface.attributes:
get_attrs.append(getterName(attr))
set_attrs.append(setterName(attr))
if info.name in get_attrs or info.name in set_attrs:
return
return_type = info.type_name
if info.name == 'addEventListener':
return_type = 'EventRemover'
self._members_emitter.Emit('\n%s $TYPE $NAME($PARAMS);\n' % javadoctemplate,
TYPE=return_type,
NAME=self.fixReservedKeyWords(info.name),
PARAMS=info.ParametersInterfaceDeclaration(),
JAVADOC=javadoc)
def AddStaticOperation(self, info, inherited):
pass
# Interfaces get secondary members directly via the superinterfaces.
def AddSecondaryAttribute(self, interface, getter, setter):
pass
def AddSecondaryOperation(self, interface, attr):
pass
def find_doc(self, name):
docid = self._interface.id
if docid not in self._docdatabase:
docid = 'HTML%s' % self._interface.id
docmembers = []
docmember = {}
if docid in self._docdatabase and 'members' in self._docdatabase[docid]:
docmembers = self._docdatabase[docid]['members']
for member in docmembers:
if member['name'] == name:
docmember = member
if 'help' in docmember:
return _escapeComments(docmember['help'])
return ""
def ucfirst(string):
"""Upper cases the 1st character in a string"""
if len(string):
return '%s%s' % (string[0].upper(), string[1:])
return string
def getterName(attr):
name = DartDomNameOfAttribute(attr)
if attr.type.id == 'boolean':
if name.startswith('is'):
name = name[2:]
return 'is%s' % ucfirst(name)
return 'get%s' % ucfirst(name)
def setterName(attr):
name = DartDomNameOfAttribute(attr)
return 'set%s' % ucfirst(name)
def getModule(annotations):
htmlaliases = ['audio', 'webaudio', 'inspector', 'offline', 'p2p', 'window', 'websockets', 'threads', 'view', 'storage', 'fileapi']
module = "dom"
if 'WebKit' in annotations and 'module' in annotations['WebKit']:
module = annotations['WebKit']['module']
if module in htmlaliases:
return "html"
if module == 'core':
return 'dom'
return module
java_lang = ['Object', 'String', 'Exception', 'DOMTimeStamp', 'DOMString']