Index: sdk/lib/html/scripts/systemhtml.py |
diff --git a/sdk/lib/html/scripts/systemhtml.py b/sdk/lib/html/scripts/systemhtml.py |
deleted file mode 100644 |
index b37838aad09dd68c674f4ef517f8378b519c667d..0000000000000000000000000000000000000000 |
--- a/sdk/lib/html/scripts/systemhtml.py |
+++ /dev/null |
@@ -1,1009 +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 provides shared functionality for the system to generate |
-Dart:html APIs from the IDL database.""" |
- |
-import emitter |
-import os |
-from generator import * |
-from htmldartgenerator import * |
- |
-_js_custom_members = set([ |
- 'AudioBufferSourceNode.start', |
- 'AudioBufferSourceNode.stop', |
- 'AudioContext.createGain', |
- 'AudioContext.createScriptProcessor', |
- 'Console.memory', |
- 'Console.profiles', |
- 'Console.assertCondition', |
- 'Console.count', |
- 'Console.debug', |
- 'Console.dir', |
- 'Console.dirxml', |
- 'Console.error', |
- 'Console.group', |
- 'Console.groupCollapsed', |
- 'Console.groupEnd', |
- 'Console.info', |
- 'Console.log', |
- 'Console.markTimeline', |
- 'Console.profile', |
- 'Console.profileEnd', |
- 'Console.time', |
- 'Console.timeEnd', |
- 'Console.timeStamp', |
- 'Console.trace', |
- 'Console.warn', |
- 'CSSStyleDeclaration.setProperty', |
- 'Element.insertAdjacentElement', |
- 'Element.insertAdjacentHTML', |
- 'Element.insertAdjacentText', |
- 'Element.remove', |
- 'ElementEvents.mouseWheel', |
- 'HTMLCanvasElement.getContext', |
- 'HTMLTableElement.createTBody', |
- 'IDBDatabase.transaction', |
- 'KeyboardEvent.initKeyboardEvent', |
- 'MouseEvent.offsetX', |
- 'MouseEvent.offsetY', |
- 'Navigator.language', |
- 'URL.createObjectURL', |
- 'URL.revokeObjectURL', |
- 'WheelEvent.wheelDeltaX', |
- 'WheelEvent.wheelDeltaY', |
- 'Window.cancelAnimationFrame', |
- 'Window.console', |
- 'Window.document', |
- 'Window.indexedDB', |
- 'Window.location', |
- 'Window.open', |
- 'Window.requestAnimationFrame', |
- 'Window.webkitCancelAnimationFrame', |
- 'Window.webkitRequestAnimationFrame', |
- 'WorkerContext.indexedDB', |
- ]) |
- |
- |
-# Classes that offer only static methods, and therefore we should suppress |
-# constructor creation. |
-_static_classes = set(['Url']) |
- |
-# Information for generating element constructors. |
-# |
-# TODO(sra): maybe remove all the argument complexity and use cascades. |
-# |
-# var c = new CanvasElement(width: 100, height: 70); |
-# var c = new CanvasElement()..width = 100..height = 70; |
-# |
-class ElementConstructorInfo(object): |
- def __init__(self, name=None, tag=None, |
- params=[], opt_params=[], |
- factory_provider_name='document'): |
- self.name = name # The constructor name 'h1' in 'HeadingElement.h1' |
- self.tag = tag or name # The HTML or SVG tag |
- self.params = params |
- self.opt_params = opt_params |
- self.factory_provider_name = factory_provider_name |
- |
- def ConstructorInfo(self, interface_name): |
- info = OperationInfo() |
- info.overloads = None |
- info.declared_name = interface_name |
- info.name = interface_name |
- info.constructor_name = self.name |
- info.js_name = None |
- info.type_name = interface_name |
- info.param_infos = map(lambda tXn: ParamInfo(tXn[1], tXn[0], True), |
- self.opt_params) |
- info.requires_named_arguments = True |
- info.factory_parameters = ['"%s"' % self.tag] |
- info.pure_dart_constructor = True |
- return info |
- |
-_html_element_constructors = { |
- 'AnchorElement' : |
- ElementConstructorInfo(tag='a', opt_params=[('DOMString', 'href')]), |
- 'AreaElement': 'area', |
- 'ButtonElement': 'button', |
- 'BRElement': 'br', |
- 'BaseElement': 'base', |
- 'BodyElement': 'body', |
- 'ButtonElement': 'button', |
- 'CanvasElement': |
- ElementConstructorInfo(tag='canvas', |
- opt_params=[('int', 'width'), ('int', 'height')]), |
- 'ContentElement': 'content', |
- 'DataListElement': 'datalist', |
- 'DListElement': 'dl', |
- 'DetailsElement': 'details', |
- 'DivElement': 'div', |
- 'EmbedElement': 'embed', |
- 'FieldSetElement': 'fieldset', |
- 'FormElement': 'form', |
- 'HRElement': 'hr', |
- 'HeadElement': 'head', |
- 'HeadingElement': [ElementConstructorInfo('h1'), |
- ElementConstructorInfo('h2'), |
- ElementConstructorInfo('h3'), |
- ElementConstructorInfo('h4'), |
- ElementConstructorInfo('h5'), |
- ElementConstructorInfo('h6')], |
- 'HtmlElement': 'html', |
- 'IFrameElement': 'iframe', |
- 'ImageElement': |
- ElementConstructorInfo(tag='img', |
- opt_params=[('DOMString', 'src'), |
- ('int', 'width'), ('int', 'height')]), |
- 'KeygenElement': 'keygen', |
- 'LIElement': 'li', |
- 'LabelElement': 'label', |
- 'LegendElement': 'legend', |
- 'LinkElement': 'link', |
- 'MapElement': 'map', |
- 'MenuElement': 'menu', |
- 'MeterElement': 'meter', |
- 'OListElement': 'ol', |
- 'ObjectElement': 'object', |
- 'OptGroupElement': 'optgroup', |
- 'OutputElement': 'output', |
- 'ParagraphElement': 'p', |
- 'ParamElement': 'param', |
- 'PreElement': 'pre', |
- 'ProgressElement': 'progress', |
- 'ScriptElement': 'script', |
- 'SelectElement': 'select', |
- 'SourceElement': 'source', |
- 'SpanElement': 'span', |
- 'StyleElement': 'style', |
- 'TableCaptionElement': 'caption', |
- 'TableCellElement': 'td', |
- 'TableColElement': 'col', |
- 'TableElement': 'table', |
- 'TableRowElement': 'tr', |
- #'TableSectionElement' <thead> <tbody> <tfoot> |
- 'TextAreaElement': 'textarea', |
- 'TitleElement': 'title', |
- 'TrackElement': 'track', |
- 'UListElement': 'ul', |
- 'VideoElement': 'video' |
-} |
- |
-_svg_element_constructors = { |
- 'AElement': 'a', |
- 'AnimateColorElement': 'animateColor', |
- 'AnimateElement': 'animate', |
- 'AnimateMotionElement': 'animateMotion', |
- 'AnimateTransformElement': 'animateTransform', |
- 'AnimationElement': 'animation', |
- 'CircleElement': 'circle', |
- 'ClipPathElement': 'clipPath', |
- 'CursorElement': 'cursor', |
- 'DefsElement': 'defs', |
- 'DescElement': 'desc', |
- 'EllipseElement': 'ellipse', |
- 'FilterElement': 'filter', |
- 'FontElement': 'font', |
- 'FontFaceElement': 'font-face', |
- 'FontFaceFormatElement': 'font-face-format', |
- 'FontFaceNameElement': 'font-face-name', |
- 'FontFaceSrcElement': 'font-face-src', |
- 'FontFaceUriElement': 'font-face-uri', |
- 'ForeignObjectElement': 'foreignObject', |
- 'GlyphElement': 'glyph', |
- 'GElement': 'g', |
- 'HKernElement': 'hkern', |
- 'ImageElement': 'image', |
- 'LinearGradientElement': 'linearGradient', |
- 'LineElement': 'line', |
- 'MarkerElement': 'marker', |
- 'MaskElement': 'mask', |
- 'MPathElement': 'mpath', |
- 'PathElement': 'path', |
- 'PatternElement': 'pattern', |
- 'PolygonElement': 'polygon', |
- 'PolylineElement': 'polyline', |
- 'RadialGradientElement': 'radialGradient', |
- 'RectElement': 'rect', |
- 'ScriptElement': 'script', |
- 'SetElement': 'set', |
- 'StopElement': 'stop', |
- 'StyleElement': 'style', |
- 'SwitchElement': 'switch', |
- 'SymbolElement': 'symbol', |
- 'TextElement': 'text', |
- 'TitleElement': 'title', |
- 'TRefElement': 'tref', |
- 'TSpanElement': 'tspan', |
- 'UseElement': 'use', |
- 'ViewElement': 'view', |
- 'VKernElement': 'vkern', |
-} |
- |
-_element_constructors = { |
- 'html': _html_element_constructors, |
- 'indexed_db': {}, |
- 'svg': _svg_element_constructors, |
- 'web_audio': {}, |
-} |
- |
-_factory_ctr_strings = { |
- 'html': { |
- 'provider_name': 'document', |
- 'constructor_name': '$dom_createElement' |
- }, |
- 'indexed_db': { |
- 'provider_name': 'document', |
- 'constructor_name': '$dom_createElement' |
- }, |
- 'svg': { |
- 'provider_name': '_SvgElementFactoryProvider', |
- 'constructor_name': 'createSvgElement_tag', |
- }, |
- 'web_audio': { |
- 'provider_name': 'document', |
- 'constructor_name': '$dom_createElement' |
- }, |
-} |
- |
-def ElementConstructorInfos(typename, element_constructors, |
- factory_provider_name='_Elements'): |
- """Returns list of ElementConstructorInfos about the convenience constructors |
- for an Element or SvgElement.""" |
- # TODO(sra): Handle multiple and named constructors. |
- if typename not in element_constructors: |
- return [] |
- infos = element_constructors[typename] |
- if isinstance(infos, str): |
- infos = ElementConstructorInfo(tag=infos, |
- factory_provider_name=factory_provider_name) |
- if not isinstance(infos, list): |
- infos = [infos] |
- return infos |
- |
-# ------------------------------------------------------------------------------ |
- |
-class HtmlDartInterfaceGenerator(object): |
- """Generates dart interface and implementation for the DOM IDL interface.""" |
- |
- def __init__(self, options, library_emitter, event_generator, interface, |
- backend): |
- self._renamer = options.renamer |
- self._database = options.database |
- self._template_loader = options.templates |
- self._type_registry = options.type_registry |
- self._options = options |
- self._library_emitter = library_emitter |
- self._event_generator = event_generator |
- self._interface = interface |
- self._backend = backend |
- self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) |
- self._library_name = self._renamer.GetLibraryName(self._interface) |
- |
- def Generate(self): |
- if 'Callback' in self._interface.ext_attrs: |
- self.GenerateCallback() |
- else: |
- self.GenerateInterface() |
- |
- def GenerateCallback(self): |
- """Generates a typedef for the callback interface.""" |
- handlers = [operation for operation in self._interface.operations |
- if operation.id == 'handleEvent'] |
- info = AnalyzeOperation(self._interface, handlers) |
- code = self._library_emitter.FileEmitter(self._interface.id, |
- self._library_name) |
- code.Emit(self._template_loader.Load('callback.darttemplate')) |
- |
- typedef_name = self._renamer.RenameInterface(self._interface) |
- code.Emit('typedef void $NAME($PARAMS);\n', |
- NAME=typedef_name, |
- PARAMS=info.ParametersDeclaration(self._DartType)) |
- self._backend.GenerateCallback(info) |
- |
- def GenerateInterface(self): |
- interface_name = self._interface_type_info.interface_name() |
- |
- factory_provider = None |
- if interface_name in interface_factories: |
- factory_provider = interface_factories[interface_name] |
- factory_constructor_name = None |
- |
- constructors = [] |
- if interface_name in _static_classes: |
- constructor_info = None |
- else: |
- constructor_info = AnalyzeConstructor(self._interface) |
- if constructor_info: |
- constructors.append(constructor_info) |
- # TODO(antonm): consider removing it later. |
- factory_provider = interface_name |
- |
- # HTML Elements and SVG Elements have convenience constructors. |
- infos = ElementConstructorInfos(interface_name, |
- _element_constructors[self._library_name], factory_provider_name= |
- _factory_ctr_strings[self._library_name]['provider_name']) |
- |
- if infos: |
- factory_constructor_name = _factory_ctr_strings[ |
- self._library_name]['constructor_name'] |
- |
- for info in infos: |
- constructors.append(info.ConstructorInfo(self._interface.id)) |
- if factory_provider: |
- assert factory_provider == info.factory_provider_name |
- else: |
- factory_provider = info.factory_provider_name |
- |
- implementation_emitter = self._ImplementationEmitter() |
- |
- base_type_info = None |
- if self._interface.parents: |
- supertype = self._interface.parents[0].type.id |
- if not IsDartCollectionType(supertype) and not IsPureInterface(supertype): |
- base_type_info = self._type_registry.TypeInfo(supertype) |
- if base_type_info.merged_into() \ |
- and self._backend.ImplementsMergedMembers(): |
- base_type_info = self._type_registry.TypeInfo( |
- base_type_info.merged_into()) |
- |
- if base_type_info: |
- base_class = base_type_info.implementation_name() |
- else: |
- base_class = self._backend.RootClassName() |
- |
- implements = self._backend.AdditionalImplementedInterfaces() |
- for parent in self._interface.parents: |
- parent_type_info = self._type_registry.TypeInfo(parent.type.id) |
- if parent_type_info.interface_name() != base_class and \ |
- parent_type_info != base_type_info: |
- implements.append(parent_type_info.interface_name()) |
- |
- secure_base_name = self._backend.SecureBaseName(interface_name) |
- if secure_base_name: |
- implements.append(secure_base_name) |
- |
- implements_str = '' |
- if implements: |
- implements_str = ' implements ' + ', '.join(set(implements)) |
- |
- annotations = FindCommonAnnotations(self._interface.doc_js_name) |
- annotations_str = '' |
- if annotations: |
- annotations_str = '\n' + '\n'.join(annotations) |
- |
- self._implementation_members_emitter = implementation_emitter.Emit( |
- self._backend.ImplementationTemplate(), |
- LIBRARYNAME=self._library_name, |
- ANNOTATIONS=annotations_str, |
- CLASSNAME=self._interface_type_info.implementation_name(), |
- EXTENDS=' extends %s' % base_class if base_class else '', |
- IMPLEMENTS=implements_str, |
- DOMNAME=self._interface.doc_js_name, |
- NATIVESPEC=self._backend.NativeSpec()) |
- self._backend.StartInterface(self._implementation_members_emitter) |
- self._backend.EmitHelpers(base_class) |
- self._backend.AddConstructors( |
- constructors, factory_provider, factory_constructor_name) |
- |
- events_class_name = self._event_generator.ProcessInterface( |
- self._interface, interface_name, |
- self._backend.CustomJSMembers(), |
- implementation_emitter) |
- if events_class_name: |
- self._backend.EmitEventGetter(events_class_name) |
- |
- merged_interface = self._interface_type_info.merged_interface() |
- if merged_interface: |
- self._backend.AddMembers(self._database.GetInterface(merged_interface), |
- not self._backend.ImplementsMergedMembers()) |
- |
- self._backend.AddMembers(self._interface) |
- self._backend.AddSecondaryMembers(self._interface) |
- self._backend.FinishInterface() |
- |
- def _ImplementationEmitter(self): |
- basename = self._interface_type_info.implementation_name() |
- if (self._interface_type_info.merged_into() and |
- self._backend.ImplementsMergedMembers()): |
- # Merged members are implemented in target interface implementation. |
- return emitter.Emitter() |
- return self._library_emitter.FileEmitter(basename, self._library_name) |
- |
- def _DartType(self, type_name): |
- return self._type_registry.DartType(type_name) |
- |
- |
-# ------------------------------------------------------------------------------ |
- |
-class Dart2JSBackend(HtmlDartGenerator): |
- """Generates a dart2js class for the dart:html library from a DOM IDL |
- interface. |
- """ |
- |
- def __init__(self, interface, options): |
- super(Dart2JSBackend, self).__init__(interface, options) |
- |
- self._database = options.database |
- self._template_loader = options.templates |
- self._type_registry = options.type_registry |
- self._renamer = options.renamer |
- self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) |
- self._current_secondary_parent = None |
- |
- def ImplementsMergedMembers(self): |
- return True |
- |
- def GenerateCallback(self, info): |
- pass |
- |
- def RootClassName(self): |
- return None |
- |
- def AdditionalImplementedInterfaces(self): |
- implements = super(Dart2JSBackend, self).AdditionalImplementedInterfaces() |
- if self._interface_type_info.list_item_type(): |
- implements.append('JavaScriptIndexingBehavior') |
- return implements |
- |
- def NativeSpec(self): |
- native_spec = MakeNativeSpec(self._interface.javascript_binding_name) |
- return ' native "%s"' % native_spec |
- |
- def ImplementationTemplate(self): |
- if IsPureInterface(self._interface.id): |
- return self._template_loader.Load('pure_interface.darttemplate') |
- |
- template_file = ('impl_%s.darttemplate' % |
- self._interface.doc_js_name) |
- return (self._template_loader.TryLoad(template_file) or |
- self._template_loader.Load('dart2js_impl.darttemplate')) |
- |
- def StartInterface(self, members_emitter): |
- self._members_emitter = members_emitter |
- |
- def FinishInterface(self): |
- pass |
- |
- def EmitStaticFactory(self, constructor_info): |
- arguments = constructor_info.ParametersAsArgumentList() |
- if arguments: |
- arguments = ', ' + arguments |
- self._members_emitter.Emit( |
- " static $INTERFACE_NAME _create($PARAMETERS_DECLARATION) => JS(" |
- "'$INTERFACE_NAME', " |
- "'new $CONSTRUCTOR_NAME($ARGUMENTS_PATTERN)'$ARGUMENTS);\n", |
- INTERFACE_NAME=self._interface_type_info.interface_name(), |
- PARAMETERS_DECLARATION=constructor_info.ParametersDeclaration( |
- self._DartType), |
- CONSTRUCTOR_NAME=constructor_info.name or self._interface.doc_js_name, |
- ARGUMENTS_PATTERN=','.join(['#'] * len(constructor_info.param_infos)), |
- ARGUMENTS=arguments) |
- |
- def SecondaryContext(self, interface): |
- if interface is not self._current_secondary_parent: |
- self._current_secondary_parent = interface |
- self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) |
- |
- def AddIndexer(self, element_type): |
- """Adds all the methods required to complete implementation of List.""" |
- # We would like to simply inherit the implementation of everything except |
- # length, [], and maybe []=. It is possible to extend from a base |
- # array implementation class only when there is no other implementation |
- # inheritance. There might be no implementation inheritance other than |
- # DOMBaseWrapper for many classes, but there might be some where the |
- # array-ness is introduced by a non-root interface: |
- # |
- # interface Y extends X, List<T> ... |
- # |
- # In the non-root case we have to choose between: |
- # |
- # class YImpl extends XImpl { add List<T> methods; } |
- # |
- # and |
- # |
- # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } |
- # |
- self._members_emitter.Emit( |
- '\n' |
- ' $TYPE operator[](int index) => JS("$TYPE", "#[#]", this, index);\n', |
- TYPE=self.SecureOutputType(element_type)) |
- |
- if 'CustomIndexedSetter' in self._interface.ext_attrs: |
- self._members_emitter.Emit( |
- '\n' |
- ' void operator[]=(int index, $TYPE value) {' |
- ' JS("void", "#[#] = #", this, index, value); }', |
- TYPE=self._NarrowInputType(element_type)) |
- else: |
- self._members_emitter.Emit( |
- '\n' |
- ' void operator[]=(int index, $TYPE value) {\n' |
- ' throw new UnsupportedError("Cannot assign element of immutable List.");\n' |
- ' }\n', |
- TYPE=self._NarrowInputType(element_type)) |
- |
- self.EmitListMixin(self._DartType(element_type)) |
- |
- def EmitAttribute(self, attribute, html_name, read_only): |
- if self._HasCustomImplementation(attribute.id): |
- return |
- |
- if IsPureInterface(self._interface.id): |
- self._AddInterfaceAttribute(attribute, html_name) |
- return |
- |
- # If the attribute is shadowing, we can't generate a shadowing |
- # field (Issue 1633). |
- # TODO(sra): _FindShadowedAttribute does not take into account the html |
- # 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) |
- if super_attribute: |
- if read_only: |
- if attribute.type.id == super_attribute.type.id: |
- # Compatible attribute, use the superclass property. This works |
- # because JavaScript will do its own dynamic dispatch. |
- self._members_emitter.Emit( |
- '\n' |
- ' // Use implementation from $SUPER.\n' |
- ' // final $TYPE $NAME;\n', |
- SUPER=super_attribute_interface, |
- NAME=html_name, |
- TYPE=self.SecureOutputType(attribute.type.id)) |
- return |
- self._members_emitter.Emit('\n // Shadowing definition.') |
- self._AddAttributeUsingProperties(attribute, html_name, read_only) |
- return |
- |
- # If the type has a conversion we need a getter or setter to contain the |
- # conversion code. |
- 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.SecureOutputType(attribute.type.id) |
- input_type = self._NarrowInputType(attribute.type.id) |
- annotations = self._Annotations(attribute.type.id, attribute.id) |
- rename = self._RenamingAnnotation(attribute.id, html_name) |
- self.EmitAttributeDocumentation(attribute) |
- if not read_only: |
- self._members_emitter.Emit( |
- '\n $RENAME$ANNOTATIONS$TYPE $NAME;' |
- '\n', |
- RENAME=rename, |
- ANNOTATIONS=annotations, |
- NAME=html_name, |
- TYPE=output_type) |
- else: |
- template = '\n $RENAME$(ANNOTATIONS)final $TYPE $NAME;\n' |
- # Need to use a getter for list.length properties so we can add a |
- # setter which throws an exception, satisfying List API. |
- if self._interface_type_info.list_item_type() and html_name == 'length': |
- template = ('\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => ' + |
- 'JS("$TYPE", "#.$NAME", this);\n') |
- self._members_emitter.Emit( |
- template, |
- RENAME=rename, |
- ANNOTATIONS=annotations, |
- NAME=html_name, |
- TYPE=output_type) |
- |
- def _AddAttributeUsingProperties(self, attribute, html_name, read_only): |
- self._AddRenamingGetter(attribute, html_name) |
- if not read_only: |
- self._AddRenamingSetter(attribute, html_name) |
- |
- def _AddInterfaceAttribute(self, attribute, html_name): |
- self._members_emitter.Emit( |
- '\n $TYPE $NAME;' |
- '\n', |
- NAME=html_name, |
- TYPE=self.SecureOutputType(attribute.type.id)) |
- |
- def _AddRenamingGetter(self, attr, html_name): |
- self.EmitAttributeDocumentation(attr) |
- |
- conversion = self._OutputConversion(attr.type.id, attr.id) |
- if conversion: |
- return self._AddConvertingGetter(attr, html_name, conversion) |
- return_type = self.SecureOutputType(attr.type.id) |
- native_type = self._NarrowToImplementationType(attr.type.id) |
- self._members_emitter.Emit( |
- # TODO(sra): Use metadata to provide native name. |
- '\n $TYPE get $HTML_NAME => JS("$NATIVE_TYPE", "#.$NAME", this);' |
- '\n', |
- HTML_NAME=html_name, |
- NAME=attr.id, |
- TYPE=return_type, |
- NATIVE_TYPE=native_type) |
- |
- def _AddRenamingSetter(self, attr, html_name): |
- self.EmitAttributeDocumentation(attr) |
- |
- conversion = self._InputConversion(attr.type.id, attr.id) |
- if conversion: |
- return self._AddConvertingSetter(attr, html_name, conversion) |
- self._members_emitter.Emit( |
- # TODO(sra): Use metadata to provide native name. |
- '\n void set $HTML_NAME($TYPE value) {' |
- '\n JS("void", "#.$NAME = #", this, value);' |
- '\n }' |
- '\n', |
- HTML_NAME=html_name, |
- NAME=attr.id, |
- TYPE=self._NarrowInputType(attr.type.id)) |
- |
- def _AddConvertingGetter(self, attr, html_name, conversion): |
- self._members_emitter.Emit( |
- '\n $RETURN_TYPE get $HTML_NAME => $CONVERT(this._$(HTML_NAME));' |
- "\n @JSName('$NAME')" |
- '\n $(ANNOTATIONS)final $NATIVE_TYPE _$HTML_NAME;' |
- '\n', |
- ANNOTATIONS=self._Annotations(attr.type.id, html_name), |
- 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( |
- # TODO(sra): Use metadata to provide native name. |
- '\n void set $HTML_NAME($INPUT_TYPE value) {' |
- '\n this._$HTML_NAME = $CONVERT(value);' |
- '\n }' |
- '\n void set _$HTML_NAME(/*$NATIVE_TYPE*/ value) {' |
- '\n JS("void", "#.$NAME = #", this, value);' |
- '\n }' |
- '\n', |
- CONVERT=conversion.function_name, |
- HTML_NAME=html_name, |
- NAME=attr.id, |
- INPUT_TYPE=conversion.input_type, |
- NATIVE_TYPE=conversion.output_type) |
- |
- def AmendIndexer(self, element_type): |
- pass |
- |
- def EmitOperation(self, info, html_name): |
- """ |
- Arguments: |
- info: An OperationInfo object. |
- """ |
- if self._HasCustomImplementation(info.name): |
- return |
- |
- self.EmitOperationDocumentation(info) |
- |
- if IsPureInterface(self._interface.id): |
- self._AddInterfaceOperation(info, html_name) |
- elif any(self._OperationRequiresConversions(op) for op in info.overloads): |
- # Any conversions needed? |
- self._AddOperationWithConversions(info, html_name) |
- else: |
- self._AddDirectNativeOperation(info, html_name) |
- |
- def _AddDirectNativeOperation(self, info, html_name): |
- self._members_emitter.Emit( |
- '\n' |
- ' $RENAME$ANNOTATIONS$MODIFIERS$TYPE $NAME($PARAMS) native;\n', |
- RENAME=self._RenamingAnnotation(info.declared_name, html_name), |
- ANNOTATIONS=self._Annotations(info.type_name, info.declared_name), |
- MODIFIERS='static ' if info.IsStatic() else '', |
- TYPE=self.SecureOutputType(info.type_name), |
- NAME=html_name, |
- PARAMS=info.ParametersDeclaration(self._NarrowInputType)) |
- |
- 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 |
- output_conversion = self._OutputConversion(info.type_name, |
- info.declared_name) |
- 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) if type_name else 'dynamic' |
- |
- body = self._members_emitter.Emit( |
- '\n' |
- ' $MODIFIERS$TYPE $(HTML_NAME)($PARAMS) {\n' |
- '$!BODY' |
- ' }\n', |
- MODIFIERS='static ' if info.IsStatic() else '', |
- TYPE=return_type, |
- HTML_NAME=html_name, |
- PARAMS=info.ParametersDeclaration(InputType)) |
- |
- parameter_names = [param_info.name for param_info in info.param_infos] |
- parameter_types = [InputType(param_info.type_id) |
- for param_info in info.param_infos] |
- operations = info.operations |
- |
- 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 |
- stmts_emitter.Emit( |
- '$(INDENT)$TYPE $NAME = $CONVERT($ARG);\n', |
- TYPE=TypeOrVar(temp_type), |
- NAME=temp_name, |
- CONVERT=conversion.function_name, |
- ARG=parameter_names[position]) |
- arguments.append(temp_name) |
- param_type = temp_type |
- verified_type = temp_type # verified by assignment in checked mode. |
- else: |
- arguments.append(parameter_names[position]) |
- param_type = self._NarrowInputType(arg.type.id) |
- # Verified by argument checking on entry to the dispatcher. |
- |
- verified_type = InputType(info.param_infos[position].type_id) |
- # The native method does not need an argument type if we know the type. |
- # But we do need the native methods to have correct function types, so |
- # be conservative. |
- if param_type == verified_type: |
- if param_type in ['String', 'num', 'int', 'double', 'bool', 'Object']: |
- param_type = 'dynamic' |
- |
- target_parameters.append( |
- '%s%s' % (TypeOrNothing(param_type), param_name)) |
- |
- argument_list = ', '.join(arguments) |
- # TODO(sra): If the native method has zero type checks, we can 'inline' is |
- # and call it directly with a JS-expression. |
- 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( |
- ' $RENAME$ANNOTATIONS$MODIFIERS$TYPE$TARGET($PARAMS) native;\n', |
- RENAME=self._RenamingAnnotation(info.declared_name, target), |
- ANNOTATIONS=self._Annotations(info.type_name, info.declared_name), |
- MODIFIERS='static ' if info.IsStatic() else '', |
- TYPE=TypeOrNothing(native_return_type), |
- TARGET=target, |
- PARAMS=', '.join(target_parameters)) |
- |
- def GenerateChecksAndCall(operation, argument_count): |
- checks = [] |
- for i in range(0, argument_count): |
- argument = operation.arguments[i] |
- parameter_name = parameter_names[i] |
- test_type = self._DartType(argument.type.id) |
- if test_type in ['dynamic', 'Object']: |
- checks.append('?%s' % parameter_name) |
- elif test_type != parameter_types[i]: |
- checks.append('(?%s && (%s is %s || %s == null))' % ( |
- parameter_name, parameter_name, test_type, parameter_name)) |
- |
- checks.extend(['!?%s' % name for name in parameter_names[argument_count:]]) |
- # There can be multiple presence checks. We need them all since a later |
- # optional argument could have been passed by name, leaving 'holes'. |
- 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 new ArgumentError("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 = '?%s' % parameter_names[position] |
- GenerateCall(operation, position + 1, [check]) |
- argument_count = position |
- GenerateCall(operation, argument_count, []) |
- |
- def _AddInterfaceOperation(self, info, html_name): |
- self._members_emitter.Emit( |
- '\n' |
- ' $TYPE $NAME($PARAMS);\n', |
- TYPE=self.SecureOutputType(info.type_name), |
- NAME=info.name, |
- PARAMS=info.ParametersDeclaration(self._NarrowInputType)) |
- |
- 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._interface.doc_js_name, member_name) |
- return member_name in _js_custom_members |
- |
- def _RenamingAnnotation(self, idl_name, member_name): |
- if member_name != idl_name: |
- return "@JSName('%s')\n " % idl_name |
- return '' |
- |
- def _Annotations(self, idl_type, idl_member_name): |
- annotations = FindDart2JSAnnotations(idl_type, self._interface.id, |
- idl_member_name) |
- if annotations: |
- return '%s\n ' % annotations |
- return_type = self.SecureOutputType(idl_type) |
- native_type = self._NarrowToImplementationType(idl_type) |
- if native_type != return_type: |
- return "@Returns('%s') @Creates('%s')\n " % (native_type, native_type) |
- else: |
- return '' |
- |
- def CustomJSMembers(self): |
- return _js_custom_members |
- |
- def _NarrowToImplementationType(self, type_name): |
- return self._type_registry.TypeInfo(type_name).narrow_dart_type() |
- |
- def _NarrowInputType(self, type_name): |
- return self._NarrowToImplementationType(type_name) |
- |
- def _FindShadowedAttribute(self, attr): |
- """Returns (attribute, superinterface) or (None, None).""" |
- def FindInParent(interface): |
- """Returns matching attribute in parent, or None.""" |
- if interface.parents: |
- parent = interface.parents[0] |
- if IsDartCollectionType(parent.type.id): |
- return (None, None) |
- if IsPureInterface(parent.type.id): |
- return (None, None) |
- if self._database.HasInterface(parent.type.id): |
- interfaces_to_search_in = [] |
- parent_interface_name = parent.type.id |
- interfaces_to_search_in.append(parent_interface_name) |
- parent_type_info = self._type_registry.TypeInfo(parent_interface_name) |
- if parent_type_info.merged_into(): |
- # IDL parent was merged into another interface, which became a |
- # parent interface in Dart. |
- parent_interface_name = parent_type_info.merged_into() |
- interfaces_to_search_in.append(parent_interface_name) |
- elif parent_type_info.merged_interface(): |
- # IDL parent has another interface that was merged into it. |
- interfaces_to_search_in.append(parent_type_info.merged_interface()) |
- |
- for interface_name in interfaces_to_search_in: |
- interface = self._database.GetInterface(interface_name) |
- attr2 = FindMatchingAttribute(interface, attr) |
- if attr2: |
- return (attr2, parent_interface_name) |
- |
- return FindInParent( |
- self._database.GetInterface(parent_interface_name)) |
- return (None, None) |
- |
- return FindInParent(self._interface) if attr else (None, None) |
- |
- def _DartType(self, type_name): |
- return self._type_registry.DartType(type_name) |
- |
-# ------------------------------------------------------------------------------ |
- |
-class DartLibraryEmitter(): |
- def __init__(self, multiemitter, dart_sources_dir, dart_libraries): |
- self._multiemitter = multiemitter |
- self._dart_sources_dir = dart_sources_dir |
- self._path_to_emitter = {} |
- self._dart_libraries = dart_libraries |
- |
- def FileEmitter(self, basename, library_name, template=None): |
- aux_dir = os.path.join(self._dart_sources_dir, library_name) |
- path = os.path.join(aux_dir, '%s.dart' % basename) |
- if not path in self._path_to_emitter: |
- emitter = self._multiemitter.FileEmitter(path) |
- if not template is None: |
- emitter = emitter.Emit(template) |
- self._path_to_emitter[path] = emitter |
- |
- self._dart_libraries.AddFile(basename, library_name, path) |
- return self._path_to_emitter[path] |
- |
- def EmitLibraries(self, auxiliary_dir): |
- self._dart_libraries.Emit(self._multiemitter, auxiliary_dir) |
- |
-# ------------------------------------------------------------------------------ |
-class DartLibrary(): |
- def __init__(self, name, template_loader, library_type, output_dir): |
- self._template = template_loader.Load( |
- '%s_%s.darttemplate' % (name, library_type)) |
- self._dart_path = os.path.join( |
- output_dir, '%s_%s.dart' % (name, library_type)) |
- self._paths = [] |
- |
- def AddFile(self, path): |
- self._paths.append(path) |
- |
- def Emit(self, emitter, auxiliary_dir): |
- def massage_path(path): |
- # The most robust way to emit path separators is to use / always. |
- return path.replace('\\', '/') |
- |
- library_emitter = emitter.FileEmitter(self._dart_path) |
- library_file_dir = os.path.dirname(self._dart_path) |
- auxiliary_dir = os.path.relpath(auxiliary_dir, library_file_dir) |
- imports_emitter = library_emitter.Emit( |
- self._template, AUXILIARY_DIR=massage_path(auxiliary_dir)) |
- |
- for path in sorted(self._paths): |
- relpath = os.path.relpath(path, library_file_dir) |
- imports_emitter.Emit( |
- "part '$PATH';\n", PATH=massage_path(relpath)) |
- |
-# ------------------------------------------------------------------------------ |
- |
-class DartLibraries(): |
- def __init__(self, libraries, template_loader, library_type, output_dir): |
- self._libraries = {} |
- for library_name in libraries: |
- self._libraries[library_name] = DartLibrary( |
- library_name, template_loader, library_type, output_dir) |
- |
- def AddFile(self, basename, library_name, path): |
- self._libraries[library_name].AddFile(path) |
- |
- def Emit(self, emitter, auxiliary_dir): |
- for lib in self._libraries.values(): |
- lib.Emit(emitter, auxiliary_dir) |