| Index: client/dom/scripts/systemhtml.py
|
| ===================================================================
|
| --- client/dom/scripts/systemhtml.py (revision 5796)
|
| +++ client/dom/scripts/systemhtml.py (working copy)
|
| @@ -1,1782 +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."""
|
| -
|
| -from systemfrog import *
|
| -from systeminterface import *
|
| -
|
| -# Members from the standard dom that should not be exposed publicly in dart:html
|
| -# but need to be exposed internally to implement dart:html on top of a standard
|
| -# browser.
|
| -_private_html_members = set([
|
| - 'Element.clientLeft',
|
| - 'Element.clientTop',
|
| - 'Element.clientWidth',
|
| - 'Element.clientHeight',
|
| - 'Element.offsetLeft',
|
| - 'Element.offsetTop',
|
| - 'Element.offsetWidth',
|
| - 'Element.offsetHeight',
|
| - 'Element.scrollLeft',
|
| - 'Element.scrollTop',
|
| - 'Element.scrollWidth',
|
| - 'Element.scrollHeight',
|
| - 'Element.childElementCount',
|
| - 'Element.firstElementChild',
|
| - 'Element.hasAttribute',
|
| - 'Element.getAttribute',
|
| - 'Element.removeAttribute',
|
| - 'Element.setAttribute',
|
| - 'Element.className',
|
| - 'Element.children',
|
| - 'Element.querySelectorAll',
|
| - 'NodeSelector.querySelectorAll',
|
| - 'Document.querySelectorAll',
|
| - 'DocumentFragment.querySelectorAll',
|
| - 'Element.getBoundingClientRect',
|
| - 'Element.getClientRects',
|
| - 'Node.appendChild',
|
| - 'Node.removeChild',
|
| - 'Node.replaceChild',
|
| - 'Node.attributes',
|
| - 'Node.childNodes',
|
| - 'Document.createElement',
|
| - 'Document.createElementNS',
|
| - 'Document.createEvent',
|
| - 'Document.createTextNode',
|
| - 'Document.createTouchList',
|
| - 'Window.getComputedStyle',
|
| - 'EventTarget.removeEventListener',
|
| - 'EventTarget.addEventListener',
|
| - 'EventTarget.dispatchEvent',
|
| - 'Event.initEvent',
|
| - 'MouseEvent.initMouseEvent',
|
| -])
|
| -
|
| -# Members from the standard dom that exist in the dart:html library with
|
| -# identical functionality but with cleaner names.
|
| -_html_library_renames = {
|
| - 'Document.defaultView': 'window',
|
| - 'DocumentFragment.querySelector': 'query',
|
| - 'NodeSelector.querySelector': 'query',
|
| - 'Element.querySelector': 'query',
|
| - 'Element.webkitMatchesSelector' : 'matchesSelector',
|
| - 'Element.scrollIntoViewIfNeeded': 'scrollIntoView',
|
| - 'Document.querySelector': 'query',
|
| - 'Node.cloneNode': 'clone',
|
| - 'Node.nextSibling': 'nextNode',
|
| - 'Node.ownerDocument': 'document',
|
| - 'Node.parentNode': 'parent',
|
| - 'Node.previousSibling': 'previousNode',
|
| - 'Node.textContent': 'text',
|
| - 'SVGElement.className': '_svgClassName',
|
| - 'SVGAnimatedString.className': '_svgClassName',
|
| - 'SVGStylable.className': '_svgClassName',
|
| -}
|
| -
|
| -#TODO(jacobr): inject annotations into the interfaces based on this table and
|
| -# on _html_library_renames.
|
| -_injected_doc_fragments = {
|
| - 'Element.query': ' /** @domName querySelector, Document.getElementById */',
|
| -}
|
| -# Members and classes from the dom that should be removed completelly from
|
| -# dart:html. These could be expressed in the IDL instead but expressing this
|
| -# as a simple table instead is more concise.
|
| -# Syntax is: ClassName.(get\.|set\.)?MemberName
|
| -# Using get: and set: is optional and should only be used when a getter needs
|
| -# to be suppressed but not the setter, etc.
|
| -# TODO(jacobr): cleanup and augment this list.
|
| -_html_library_remove = set([
|
| - 'Window.get:document', # Removed as we have a custom implementation.
|
| - 'NodeList.item',
|
| - "Attr.*",
|
| -# "BarProp.*",
|
| -# "BarInfo.*",
|
| -# "Blob.webkitSlice",
|
| -# "CDATASection.*",
|
| -# "Comment.*",
|
| -# "DOMImplementation.*",
|
| - "Document.get:documentElement",
|
| - "Document.get:forms",
|
| -# "Document.get:selectedStylesheetSet",
|
| -# "Document.set:selectedStylesheetSet",
|
| -# "Document.get:preferredStylesheetSet",
|
| - "Document.get:links",
|
| - "Document.getElementsByTagName",
|
| - "Document.set:domain",
|
| - "Document.get:implementation",
|
| - "Document.createAttributeNS",
|
| - "Document.get:inputEncoding",
|
| - "Document.getElementById",
|
| - "Document.getElementsByClassName",
|
| - "Document.get:height",
|
| - "Document.get:width",
|
| - "Element.getElementsByClassName",
|
| - "Element.getElementsByTagNameNS",
|
| - "Element.getElementsByTagName",
|
| - "Document.get:compatMode",
|
| - "Document.importNode",
|
| - "Document.evaluate",
|
| - "Document.get:images",
|
| - "Document.querySelector",
|
| - "Document.createExpression",
|
| - "Document.getOverrideStyle",
|
| - "Document.xmlStandalone",
|
| - "Document.createComment",
|
| - "Document.adoptNode",
|
| - "Document.get:characterSet",
|
| - "Document.createAttribute",
|
| - "Document.querySelectorAll",
|
| - "Document.get:URL",
|
| - "Document.createEntityReference",
|
| - "Document.get:documentURI",
|
| - "Document.set:documentURI",
|
| - "Document.createNodeIterator",
|
| - "Document.createProcessingInstruction",
|
| - "Document.get:doctype",
|
| - "Document.getElementsByName",
|
| - "Document.createTreeWalker",
|
| - "Document.location",
|
| - "Document.createNSResolver",
|
| - "Document.get:xmlEncoding",
|
| - "Document.get:defaultCharset",
|
| - "Document.get:applets",
|
| - "Document.getSelection",
|
| - "Document.xmlVersion",
|
| - "Document.get:anchors",
|
| - "Document.getElementsByTagNameNS",
|
| - "DocumentType.*",
|
| - "Element.hasAttributeNS",
|
| - "Element.getAttributeNS",
|
| - "Element.setAttributeNode",
|
| - "Element.getAttributeNode",
|
| - "Element.removeAttributeNode",
|
| - "Element.removeAttributeNS",
|
| - "Element.setAttributeNodeNS",
|
| - "Element.getAttributeNodeNS",
|
| - "Element.setAttributeNS",
|
| - "BodyElement.text",
|
| - "AnchorElement.text",
|
| - "OptionElement.text",
|
| - "ScriptElement.text",
|
| - "TitleElement.text",
|
| -# "EventSource.get:url",
|
| -# TODO(jacobr): should these be removed?
|
| - "Document.close",
|
| - "Document.hasFocus",
|
| -
|
| - "Document.vlinkColor",
|
| - "Document.captureEvents",
|
| - "Document.releaseEvents",
|
| - "Document.get:compatMode",
|
| - "Document.designMode",
|
| - "Document.dir",
|
| - "Document.all",
|
| - "Document.write",
|
| - "Document.fgColor",
|
| - "Document.bgColor",
|
| - "Document.get:plugins",
|
| - "Document.alinkColor",
|
| - "Document.get:embeds",
|
| - "Document.open",
|
| - "Document.clear",
|
| - "Document.get:scripts",
|
| - "Document.writeln",
|
| - "Document.linkColor",
|
| - "Element.get:itemRef",
|
| - "Element.outerText",
|
| - "Element.accessKey",
|
| - "Element.get:itemType",
|
| - "Element.innerText",
|
| - "Element.set:outerHTML",
|
| - "Element.itemScope",
|
| - "Element.itemValue",
|
| - "Element.itemId",
|
| - "Element.get:itemProp",
|
| - 'Element.scrollIntoView',
|
| - 'Element.get:classList',
|
| - "EmbedElement.getSVGDocument",
|
| - "FormElement.get:elements",
|
| - "HTMLFrameElement.*",
|
| - "HTMLFrameSetElement.*",
|
| - "HtmlElement.version",
|
| - "HtmlElement.manifest",
|
| - "Document.version",
|
| - "Document.manifest",
|
| -# "IFrameElement.getSVGDocument", #TODO(jacobr): should this be removed
|
| - "InputElement.dirName",
|
| - "HTMLIsIndexElement.*",
|
| - "ObjectElement.getSVGDocument",
|
| - "HTMLOptionsCollection.*",
|
| - "HTMLPropertiesCollection.*",
|
| - "SelectElement.remove",
|
| - "TextAreaElement.dirName",
|
| - "NamedNodeMap.*",
|
| - "Node.isEqualNode",
|
| - "Node.get:TEXT_NODE",
|
| - "Node.hasAttributes",
|
| - "Node.get:DOCUMENT_TYPE_NODE",
|
| - "Node.get:DOCUMENT_POSITION_FOLLOWING",
|
| - "Node.lookupNamespaceURI",
|
| - "Node.get:ELEMENT_NODE",
|
| - "Node.get:namespaceURI",
|
| - "Node.get:DOCUMENT_FRAGMENT_NODE",
|
| - "Node.get:localName",
|
| - "Node.dispatchEvent",
|
| - "Node.isDefaultNamespace",
|
| - "Node.compareDocumentPosition",
|
| - "Node.get:baseURI",
|
| - "Node.isSameNode",
|
| - "Node.get:DOCUMENT_POSITION_DISCONNECTED",
|
| - "Node.get:DOCUMENT_NODE",
|
| - "Node.get:DOCUMENT_POSITION_CONTAINS",
|
| - "Node.get:COMMENT_NODE",
|
| - "Node.get:ENTITY_REFERENCE_NODE",
|
| - "Node.isSupported",
|
| - "Node.get:firstChild",
|
| - "Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC",
|
| - "Node.get:lastChild",
|
| - "Node.get:NOTATION_NODE",
|
| - "Node.normalize",
|
| - "Node.get:parentElement",
|
| - "Node.get:ATTRIBUTE_NODE",
|
| - "Node.get:ENTITY_NODE",
|
| - "Node.get:DOCUMENT_POSITION_CONTAINED_BY",
|
| - "Node.get:prefix",
|
| - "Node.set:prefix",
|
| - "Node.get:DOCUMENT_POSITION_PRECEDING",
|
| - "Node.get:nodeType",
|
| - "Node.removeEventListener",
|
| - "Node.get:nodeValue",
|
| - "Node.set:nodeValue",
|
| - "Node.get:CDATA_SECTION_NODE",
|
| - "Node.get:nodeName",
|
| - "Node.addEventListener",
|
| - "Node.lookupPrefix",
|
| - "Node.get:PROCESSING_INSTRUCTION_NODE",
|
| - "Notification.dispatchEvent",
|
| - "Notification.addEventListener",
|
| - "Notification.removeEventListener"])
|
| -
|
| -# Events without onEventName attributes in the IDL we want to support.
|
| -# We can automatically extract most event event names by checking for
|
| -# onEventName methods in the IDL but some events aren't listed so we need
|
| -# to manually add them here so that they are easy for users to find.
|
| -_html_manual_events = {
|
| - 'Element': ['touchleave', 'webkitTransitionEnd'],
|
| - 'Window': ['DOMContentLoaded']
|
| -}
|
| -
|
| -# These event names must be camel case when attaching event listeners
|
| -# using addEventListener even though the onEventName properties in the DOM for
|
| -# them are not camel case.
|
| -_on_attribute_to_event_name_mapping = {
|
| - 'webkitanimationend': 'webkitAnimationEnd',
|
| - 'webkitanimationiteration': 'webkitAnimationIteration',
|
| - 'webkitanimationstart': 'webkitAnimationStart',
|
| - 'webkitspeechchange': 'webkitSpeechChange',
|
| - 'webkittransitionend': 'webkitTransitionEnd',
|
| -}
|
| -
|
| -# Mapping from raw event names to the pretty camelCase event names exposed as
|
| -# properties in dart:html. If the DOM exposes a new event name, you will need
|
| -# to add the lower case to camel case conversion for that event name here.
|
| -_html_event_names = {
|
| - 'DOMContentLoaded': 'contentLoaded',
|
| - 'touchleave': 'touchLeave',
|
| - 'abort': 'abort',
|
| - 'beforecopy': 'beforeCopy',
|
| - 'beforecut': 'beforeCut',
|
| - 'beforepaste': 'beforePaste',
|
| - 'beforeunload': 'beforeUnload',
|
| - 'blur': 'blur',
|
| - 'cached': 'cached',
|
| - 'canplay': 'canPlay',
|
| - 'canplaythrough': 'canPlayThrough',
|
| - 'change': 'change',
|
| - 'checking': 'checking',
|
| - 'click': 'click',
|
| - 'close': 'close',
|
| - 'contextmenu': 'contextMenu',
|
| - 'copy': 'copy',
|
| - 'cut': 'cut',
|
| - 'dblclick': 'doubleClick',
|
| - 'devicemotion': 'deviceMotion',
|
| - 'deviceorientation': 'deviceOrientation',
|
| - 'display': 'display',
|
| - 'downloading': 'downloading',
|
| - 'drag': 'drag',
|
| - 'dragend': 'dragEnd',
|
| - 'dragenter': 'dragEnter',
|
| - 'dragleave': 'dragLeave',
|
| - 'dragover': 'dragOver',
|
| - 'dragstart': 'dragStart',
|
| - 'drop': 'drop',
|
| - 'durationchange': 'durationChange',
|
| - 'emptied': 'emptied',
|
| - 'ended': 'ended',
|
| - 'error': 'error',
|
| - 'focus': 'focus',
|
| - 'hashchange': 'hashChange',
|
| - 'input': 'input',
|
| - 'invalid': 'invalid',
|
| - 'keydown': 'keyDown',
|
| - 'keypress': 'keyPress',
|
| - 'keyup': 'keyUp',
|
| - 'load': 'load',
|
| - 'loadeddata': 'loadedData',
|
| - 'loadedmetadata': 'loadedMetadata',
|
| - 'loadend': 'loadEnd',
|
| - 'loadstart': 'loadStart',
|
| - 'message': 'message',
|
| - 'mousedown': 'mouseDown',
|
| - 'mousemove': 'mouseMove',
|
| - 'mouseout': 'mouseOut',
|
| - 'mouseover': 'mouseOver',
|
| - 'mouseup': 'mouseUp',
|
| - 'mousewheel': 'mouseWheel',
|
| - 'noupdate': 'noUpdate',
|
| - 'obsolete': 'obsolete',
|
| - 'offline': 'offline',
|
| - 'online': 'online',
|
| - 'open': 'open',
|
| - 'pagehide': 'pageHide',
|
| - 'pageshow': 'pageShow',
|
| - 'paste': 'paste',
|
| - 'pause': 'pause',
|
| - 'play': 'play',
|
| - 'playing': 'playing',
|
| - 'popstate': 'popState',
|
| - 'progress': 'progress',
|
| - 'ratechange': 'rateChange',
|
| - 'readystatechange': 'readyStateChange',
|
| - 'reset': 'reset',
|
| - 'resize': 'resize',
|
| - 'scroll': 'scroll',
|
| - 'search': 'search',
|
| - 'seeked': 'seeked',
|
| - 'seeking': 'seeking',
|
| - 'select': 'select',
|
| - 'selectionchange': 'selectionChange',
|
| - 'selectstart': 'selectStart',
|
| - 'show': 'show',
|
| - 'stalled': 'stalled',
|
| - 'storage': 'storage',
|
| - 'submit': 'submit',
|
| - 'suspend': 'suspend',
|
| - 'timeupdate': 'timeUpdate',
|
| - 'touchcancel': 'touchCancel',
|
| - 'touchend': 'touchEnd',
|
| - 'touchmove': 'touchMove',
|
| - 'touchstart': 'touchStart',
|
| - 'unload': 'unload',
|
| - 'updateready': 'updateReady',
|
| - 'volumechange': 'volumeChange',
|
| - 'waiting': 'waiting',
|
| - 'webkitAnimationEnd': 'animationEnd',
|
| - 'webkitAnimationIteration': 'animationIteration',
|
| - 'webkitAnimationStart': 'animationStart',
|
| - 'webkitfullscreenchange': 'fullscreenChange',
|
| - 'webkitfullscreenerror': 'fullscreenError',
|
| - 'webkitSpeechChange': 'speechChange',
|
| - 'webkitTransitionEnd': 'transitionEnd'
|
| -}
|
| -
|
| -# These classes require an explicit declaration for the "on" method even though
|
| -# they don't declare any unique events, because the concrete class hierarchy
|
| -# doesn't match the interface hierarchy.
|
| -_html_explicit_event_classes = set(['DocumentFragment'])
|
| -
|
| -def _OnAttributeToEventName(on_method):
|
| - event_name = on_method.id[2:]
|
| - if event_name in _on_attribute_to_event_name_mapping:
|
| - return _on_attribute_to_event_name_mapping[event_name]
|
| - else:
|
| - return event_name
|
| -
|
| -def _DomToHtmlEvents(interface_id, events):
|
| - event_names = set(map(_OnAttributeToEventName, events))
|
| - if interface_id in _html_manual_events:
|
| - for manual_event_name in _html_manual_events[interface_id]:
|
| - event_names.add(manual_event_name)
|
| -
|
| - return sorted(event_names, key=lambda name: _html_event_names[name])
|
| -
|
| -# ------------------------------------------------------------------------------
|
| -class HtmlSystemShared(object):
|
| -
|
| - def __init__(self, database, generator):
|
| - self._event_classes = set()
|
| - self._seen_event_names = {}
|
| - self._database = database
|
| - self._generator = generator
|
| -
|
| - def _AllowInHtmlLibrary(self, interface, member, member_prefix):
|
| - return not self._Matches(interface, member, member_prefix,
|
| - _html_library_remove)
|
| -
|
| - def _Matches(self, interface, member, member_prefix, candidates):
|
| - for interface_name in self._AllAncestorInterfaces(interface):
|
| - if (DartType(interface_name) + '.' + member in candidates or
|
| - DartType(interface_name) + '.' + member_prefix + member in candidates):
|
| - return True
|
| - return False
|
| -
|
| - def MaybeReturnDocument(self, return_type):
|
| - """
|
| - To make it appear that there are not a distinct Document and
|
| - HTMLHtmlElement (document.documentElement) objects we always use
|
| - documentElement instead of the regular document object so must not
|
| - allow a regular document to leak out.
|
| - """
|
| - # TODO(jacobr): any method that returns a Node could also theoretically
|
| - # really return a Document but there are alot of methods that return nodes
|
| - # and they all appear to be safe. Consider the alternate strategy of
|
| - # whitelisting just the known safe methods that return Nodes.
|
| - return (DartType(return_type) == 'EventTarget' or
|
| - DartType(return_type) == 'Document')
|
| -
|
| - def _AllAncestorInterfaces(self, interface):
|
| - interfaces = ([interface.id] +
|
| - self._generator._AllImplementedInterfaces(interface))
|
| - return interfaces
|
| -
|
| - def RenameInHtmlLibrary(self, interface, member, member_prefix=''):
|
| - """
|
| - Returns the name of the member in the HTML library or None if the member is
|
| - suppressed in the HTML library
|
| - """
|
| - if not self._AllowInHtmlLibrary(interface, member, member_prefix):
|
| - return None
|
| -
|
| - for interface_name in self._AllAncestorInterfaces(interface):
|
| - name = interface_name + '.' + member
|
| - if name in _html_library_renames:
|
| - return _html_library_renames[name]
|
| - name = interface.id + '.' + member_prefix + member
|
| - if name in _html_library_renames:
|
| - return _html_library_renames[name]
|
| -
|
| - if self._PrivateInHtmlLibrary(interface, member, member_prefix):
|
| - return '_' + member
|
| -
|
| - # No rename required
|
| - return member
|
| -
|
| - def _PrivateInHtmlLibrary(self, interface, member, member_prefix):
|
| - return self._Matches(interface, member, member_prefix,
|
| - _private_html_members)
|
| -
|
| - # TODO(jacobr): this already exists
|
| - def _TraverseParents(self, interface, callback):
|
| - for parent in interface.parents:
|
| - parent_id = parent.type.id
|
| - if self._database.HasInterface(parent_id):
|
| - parent_interface = self._database.GetInterface(parent_id)
|
| - callback(parent_interface)
|
| - self._TraverseParents(parent_interface, callback)
|
| -
|
| - # TODO(jacobr): this isn't quite right....
|
| - def GetParentsEventsClasses(self, interface):
|
| - # Ugly hack as we don't specify that Document and DocumentFragment inherit
|
| - # from Element in our IDL.
|
| - if interface.id == 'Document' or interface.id == 'DocumentFragment':
|
| - return ['ElementEvents']
|
| -
|
| - interfaces_with_events = set()
|
| - def visit(parent):
|
| - if parent.id in self._event_classes:
|
| - interfaces_with_events.add(parent)
|
| -
|
| - self._TraverseParents(interface, visit)
|
| - if len(interfaces_with_events) == 0:
|
| - return ['Events']
|
| - else:
|
| - names = []
|
| - for interface in interfaces_with_events:
|
| - names.append(interface.id + 'Events')
|
| - return names
|
| -
|
| - def GetParentEventsClass(self, interface):
|
| - parent_event_classes = self.GetParentsEventsClasses(interface)
|
| - if len(parent_event_classes) != 1:
|
| - raise Exception('Only one parent event class allowed ' + interface.id)
|
| - return parent_event_classes[0]
|
| -
|
| - def _ImplClassName(self, type_name):
|
| - return '_' + type_name + 'Impl'
|
| -
|
| - # This returns two values: the first is whether or not an "on" property should
|
| - # be generated for the interface, and the second is the event attributes to
|
| - # generate if it should.
|
| - def GetEventAttributes(self, interface):
|
| - events = set([attr for attr in interface.attributes
|
| - if self._generator._IsEventAttribute(interface, attr)])
|
| -
|
| - if events or interface.id in _html_explicit_event_classes:
|
| - return True, events
|
| - else:
|
| - return False, None
|
| -
|
| - def IsPrivate(self, name):
|
| - return name.startswith('_')
|
| -
|
| -class HtmlSystem(System):
|
| -
|
| - def __init__(self, templates, database, emitters, output_dir, generator):
|
| - super(HtmlSystem, self).__init__(
|
| - templates, database, emitters, output_dir)
|
| - self._shared = HtmlSystemShared(database, generator)
|
| -
|
| -class HtmlInterfacesSystem(HtmlSystem):
|
| -
|
| - def __init__(self, templates, database, emitters, output_dir, generator):
|
| - super(HtmlInterfacesSystem, self).__init__(
|
| - templates, database, emitters, output_dir, generator)
|
| - self._dart_interface_file_paths = []
|
| -
|
| - def InterfaceGenerator(self,
|
| - interface,
|
| - common_prefix,
|
| - super_interface_name,
|
| - source_filter):
|
| - """."""
|
| - interface_name = interface.id
|
| - dart_interface_file_path = self._FilePathForDartInterface(interface_name)
|
| -
|
| - self._dart_interface_file_paths.append(dart_interface_file_path)
|
| -
|
| - dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path)
|
| -
|
| - template_file = 'interface_%s.darttemplate' % interface_name
|
| - template = self._templates.TryLoad(template_file)
|
| - if not template:
|
| - template = self._templates.Load('interface.darttemplate')
|
| -
|
| - return HtmlDartInterfaceGenerator(
|
| - interface, dart_interface_code,
|
| - template,
|
| - common_prefix, super_interface_name,
|
| - source_filter, self, self._shared)
|
| -
|
| - def ProcessCallback(self, interface, info):
|
| - """Generates a typedef for the callback interface."""
|
| - interface_name = interface.id
|
| - file_path = self._FilePathForDartInterface(interface_name)
|
| - self._ProcessCallback(interface, info, file_path)
|
| -
|
| - def GenerateLibraries(self, lib_dir):
|
| - pass
|
| -
|
| -
|
| - def _FilePathForDartInterface(self, interface_name):
|
| - """Returns the file path of the Dart interface definition."""
|
| - # TODO(jmesserly): is this the right path
|
| - return os.path.join(self._output_dir, 'html', 'interface',
|
| - '%s.dart' % interface_name)
|
| -
|
| -# ------------------------------------------------------------------------------
|
| -
|
| -# TODO(jmesserly): inheritance is probably not the right way to factor this long
|
| -# term, but it makes merging better for now.
|
| -class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
|
| - """Generates Dart Interface definition for one DOM IDL interface."""
|
| -
|
| - def __init__(self, interface, emitter, template,
|
| - common_prefix, super_interface, source_filter, system, shared):
|
| - super(HtmlDartInterfaceGenerator, self).__init__(interface,
|
| - emitter, template, common_prefix, super_interface, source_filter)
|
| - self._system = system
|
| - self._shared = shared
|
| -
|
| - def StartInterface(self):
|
| - typename = self._interface.id
|
| -
|
| - extends = []
|
| - suppressed_extends = []
|
| -
|
| - for parent in self._interface.parents:
|
| - # TODO(vsm): Remove source_filter.
|
| - if MatchSourceFilter(self._source_filter, parent):
|
| - # Parent is a DOM type.
|
| - extends.append(DartType(parent.type.id))
|
| - elif '<' in parent.type.id:
|
| - # Parent is a Dart collection type.
|
| - # TODO(vsm): Make this check more robust.
|
| - extends.append(DartType(parent.type.id))
|
| - else:
|
| - suppressed_extends.append('%s.%s' %
|
| - (self._common_prefix, DartType(parent.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)
|
| - if constructor_info:
|
| - factory_provider = '_' + typename + 'FactoryProvider';
|
| -
|
| - if typename in interface_factories:
|
| - factory_provider = interface_factories[typename]
|
| -
|
| - if factory_provider:
|
| - extends_str += ' default ' + factory_provider
|
| -
|
| - # 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)
|
| -
|
| - 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);\n',
|
| - CTOR=self._interface.id,
|
| - TYPE=DartType(element_type))
|
| -
|
| - emit_events, events = self._shared.GetEventAttributes(self._interface)
|
| - if not emit_events:
|
| - return
|
| - elif events:
|
| - self.AddEventAttributes(events)
|
| - else:
|
| - self._EmitEventGetter(self._shared.GetParentEventsClass(self._interface))
|
| -
|
| - def AddAttribute(self, getter, setter):
|
| - html_getter_name = self._shared.RenameInHtmlLibrary(
|
| - self._interface, DartDomNameOfAttribute(getter), 'get:')
|
| - html_setter_name = self._shared.RenameInHtmlLibrary(
|
| - self._interface, DartDomNameOfAttribute(getter), 'set:')
|
| -
|
| - if not html_getter_name or self._shared.IsPrivate(html_getter_name):
|
| - getter = None
|
| - if not html_setter_name or self._shared.IsPrivate(html_setter_name):
|
| - setter = None
|
| - if not getter and not setter:
|
| - return
|
| -
|
| - # We don't yet handle inconsistent renames of the getter and setter yet.
|
| - if html_getter_name and html_setter_name:
|
| - assert html_getter_name == html_setter_name
|
| - if (getter and setter and
|
| - DartType(getter.type.id) == DartType(setter.type.id)):
|
| - self._members_emitter.Emit('\n $TYPE $NAME;\n',
|
| - NAME=html_getter_name,
|
| - TYPE=DartType(getter.type.id));
|
| - return
|
| - if getter and not setter:
|
| - self._members_emitter.Emit('\n final $TYPE $NAME;\n',
|
| - NAME=html_getter_name,
|
| - TYPE=DartType(getter.type.id));
|
| - return
|
| - raise Exception('Unexpected getter/setter combination %s %s' %
|
| - (getter, setter))
|
| -
|
| - def AddOperation(self, info):
|
| - """
|
| - Arguments:
|
| - operations - contains the overloads, one or more operations with the same
|
| - name.
|
| - """
|
| - html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
|
| - if html_name and not self._shared.IsPrivate(html_name):
|
| - self._members_emitter.Emit('\n'
|
| - ' $TYPE $NAME($PARAMS);\n',
|
| - TYPE=info.type_name,
|
| - NAME=html_name,
|
| - PARAMS=info.ParametersInterfaceDeclaration())
|
| -
|
| - def FinishInterface(self):
|
| - pass
|
| -
|
| - def AddConstant(self, constant):
|
| - self._EmitConstant(self._members_emitter, constant)
|
| -
|
| - def AddEventAttributes(self, event_attrs):
|
| - event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
|
| - self._shared._event_classes.add(self._interface.id)
|
| - events_interface = self._interface.id + 'Events'
|
| - self._EmitEventGetter(events_interface)
|
| -
|
| - events_members = self._emitter.Emit(
|
| - '\ninterface $INTERFACE extends $PARENTS {\n$!MEMBERS}\n',
|
| - INTERFACE=events_interface,
|
| - PARENTS=', '.join(
|
| - self._shared.GetParentsEventsClasses(self._interface)))
|
| -
|
| - for event_name in event_attrs:
|
| - if event_name in _html_event_names:
|
| - events_members.Emit('\n EventListenerList get $NAME();\n',
|
| - NAME=_html_event_names[event_name])
|
| - else:
|
| - raise Exception('No known html even name for event: ' + event_name)
|
| -
|
| - def _EmitEventGetter(self, events_interface):
|
| - self._members_emitter.Emit('\n $TYPE get on();\n',
|
| - TYPE=events_interface)
|
| -
|
| -# ------------------------------------------------------------------------------
|
| -
|
| -# TODO(jmesserly): inheritance is probably not the right way to factor this long
|
| -# term, but it makes merging better for now.
|
| -class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| - """Generates a Frog class for the dart:html library from a DOM IDL
|
| - interface.
|
| - """
|
| -
|
| - def __init__(self, system, interface, template, super_interface, dart_code,
|
| - shared):
|
| - super(HtmlFrogClassGenerator, self).__init__(
|
| - system, interface, template, super_interface, dart_code)
|
| - self._shared = shared
|
| -
|
| - def _ImplClassName(self, type_name):
|
| - return self._shared._ImplClassName(type_name)
|
| -
|
| - def StartInterface(self):
|
| - interface = self._interface
|
| - interface_name = interface.id
|
| -
|
| - self._class_name = self._ImplClassName(interface_name)
|
| -
|
| - base = None
|
| - if interface.parents:
|
| - supertype = interface.parents[0].type.id
|
| - if IsDartCollectionType(supertype):
|
| - # List methods are injected in AddIndexer.
|
| - pass
|
| - else:
|
| - base = self._ImplClassName(supertype)
|
| -
|
| - native_spec = MakeNativeSpec(interface.javascript_binding_name)
|
| -
|
| - extends = ' extends ' + base if base else ''
|
| -
|
| - # TODO: Include all implemented interfaces, including other Lists.
|
| - implements = [interface_name]
|
| - element_type = MaybeTypedArrayElementType(self._interface)
|
| - if element_type:
|
| - implements.append('List<%s>' % DartType(element_type))
|
| -
|
| - self._members_emitter = self._dart_code.Emit(
|
| - self._template,
|
| - #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
|
| - #$!MEMBERS
|
| - #}
|
| - CLASSNAME=self._class_name,
|
| - EXTENDS=extends,
|
| - IMPLEMENTS=' implements ' + ', '.join(implements),
|
| - NATIVESPEC=' native "' + native_spec + '"')
|
| -
|
| - if element_type:
|
| - self.AddTypedArrayConstructors(element_type)
|
| -
|
| - # Emit a factory provider class for the constructor.
|
| - constructor_info = AnalyzeConstructor(interface)
|
| - if constructor_info:
|
| - self._EmitFactoryProvider(interface_name, constructor_info)
|
| -
|
| - emit_events, events = self._shared.GetEventAttributes(self._interface)
|
| - if not emit_events:
|
| - return
|
| - elif events:
|
| - self.AddEventAttributes(events)
|
| - else:
|
| - parent_events_class = self._shared.GetParentEventsClass(self._interface)
|
| - self._EmitEventGetter('_' + parent_events_class + 'Impl')
|
| -
|
| - def _EmitFactoryProvider(self, interface_name, constructor_info):
|
| - template_file = 'factoryprovider_%s.darttemplate' % interface_name
|
| - template = self._system._templates.TryLoad(template_file)
|
| - if not template:
|
| - template = self._system._templates.Load('factoryprovider.darttemplate')
|
| -
|
| - factory_provider = '_' + interface_name + 'FactoryProvider'
|
| - emitter = self._system._ImplFileEmitter(factory_provider)
|
| - emitter.Emit(
|
| - template,
|
| - FACTORYPROVIDER=factory_provider,
|
| - CONSTRUCTOR=interface_name,
|
| - PARAMETERS=constructor_info.ParametersImplementationDeclaration(),
|
| - NAMED_CONSTRUCTOR=constructor_info.name or interface_name,
|
| - ARGUMENTS=constructor_info.ParametersAsArgumentList())
|
| -
|
| - 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
|
| - # get 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) native "return this[index];";\n',
|
| - TYPE=self._NarrowOutputType(element_type))
|
| -
|
| - if 'CustomIndexedSetter' in self._interface.ext_attrs:
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' void operator[]=(int index, $TYPE value) native "this[index] = value";\n',
|
| - TYPE=self._NarrowInputType(element_type))
|
| - else:
|
| - # The HTML library implementation of NodeList has a custom indexed setter
|
| - # implementation that uses the parent node the NodeList is associated
|
| - # with if one is available.
|
| - if self._interface.id != 'NodeList':
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' void operator[]=(int index, $TYPE value) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
|
| - ' }\n',
|
| - TYPE=self._NarrowInputType(element_type))
|
| -
|
| - # TODO(sra): Use separate mixins for mutable implementations of List<T>.
|
| - # TODO(sra): Use separate mixins for typed array implementations of List<T>.
|
| - if self._interface.id != 'NodeList':
|
| - template_file = 'immutable_list_mixin.darttemplate'
|
| - template = self._system._templates.Load(template_file)
|
| - self._members_emitter.Emit(template, E=DartType(element_type))
|
| -
|
| - def AddAttribute(self, getter, setter):
|
| -
|
| - html_getter_name = self._shared.RenameInHtmlLibrary(
|
| - self._interface, DartDomNameOfAttribute(getter), 'get:')
|
| - html_setter_name = self._shared.RenameInHtmlLibrary(
|
| - self._interface, DartDomNameOfAttribute(getter), 'set:')
|
| -
|
| - if not html_getter_name:
|
| - getter = None
|
| - if not html_setter_name:
|
| - setter = None
|
| -
|
| - if not getter and not setter:
|
| - return
|
| -
|
| - if ((getter and (html_getter_name != getter.id or
|
| - self._shared.MaybeReturnDocument(getter.type.id))) or
|
| - (setter and (html_setter_name != setter.id or
|
| - self._shared.MaybeReturnDocument(setter.type.id))) or
|
| - self._interface.id == 'Document'):
|
| - if getter:
|
| - self._AddRenamingGetter(getter, html_getter_name)
|
| - if setter:
|
| - self._AddRenamingSetter(setter, html_setter_name)
|
| - return
|
| -
|
| - # If the (getter, setter) pair is shadowing, we can't generate a shadowing
|
| - # field (Issue 1633).
|
| - (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter)
|
| - (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter)
|
| - if super_getter or super_setter:
|
| - if getter and not setter and super_getter and not super_setter:
|
| - if DartType(getter.type.id) == DartType(super_getter.type.id):
|
| - # Compatible getter, use the superclass property. This works because
|
| - # JavaScript will do its own dynamic dispatch.
|
| - output_type = getter and self._NarrowOutputType(getter.type.id)
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' // Use implementation from $SUPER.\n'
|
| - ' // final $TYPE $NAME;\n',
|
| - SUPER=super_getter_interface.id,
|
| - NAME=DartDomNameOfAttribute(getter),
|
| - TYPE=output_type)
|
| - return
|
| -
|
| - self._members_emitter.Emit('\n // Shadowing definition.')
|
| - self._AddAttributeUsingProperties(getter, setter)
|
| - return
|
| -
|
| - output_type = getter and self._NarrowOutputType(getter.type.id)
|
| - input_type = setter and self._NarrowInputType(setter.type.id)
|
| - if getter and setter and input_type == output_type:
|
| - self._members_emitter.Emit(
|
| - '\n $TYPE $NAME;\n',
|
| - NAME=DartDomNameOfAttribute(getter),
|
| - TYPE=output_type)
|
| - return
|
| - if getter and not setter:
|
| - self._members_emitter.Emit(
|
| - '\n final $TYPE $NAME;\n',
|
| - NAME=DartDomNameOfAttribute(getter),
|
| - TYPE=output_type)
|
| - return
|
| - self._AddAttributeUsingProperties(getter, setter)
|
| -
|
| - def _AddAttributeUsingProperties(self, getter, setter):
|
| - if getter:
|
| - self._AddGetter(getter)
|
| - if setter:
|
| - self._AddSetter(setter)
|
| -
|
| - def _AddGetter(self, attr):
|
| - self._AddRenamingGetter(attr, DartDomNameOfAttribute(attr))
|
| -
|
| - def _AddSetter(self, attr):
|
| - self._AddRenamingSetter(attr, DartDomNameOfAttribute(attr))
|
| -
|
| - def _AddRenamingGetter(self, attr, html_name):
|
| - return_type = self._NarrowOutputType(attr.type.id)
|
| - if self._shared.MaybeReturnDocument(attr.type.id):
|
| - self._members_emitter.Emit(
|
| - '\n $TYPE get $(HTML_NAME)() => '
|
| - '_FixHtmlDocumentReference(_$(HTML_NAME));\n',
|
| - HTML_NAME=html_name,
|
| - TYPE=return_type)
|
| - html_name = '_' + html_name
|
| - # For correctness this needs to be the return type of the native helper
|
| - # method due to the fact that the real HTMLDocument object is not typed
|
| - # as a document. TODO(jacobr): we could simplify this.
|
| - return_type = '_EventTargetImpl'
|
| -
|
| - self._members_emitter.Emit(
|
| - '\n $TYPE get $(HTML_NAME)() native "return $(THIS).$NAME;";\n',
|
| - HTML_NAME=html_name,
|
| - NAME=attr.id,
|
| - TYPE=return_type,
|
| - THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
|
| -
|
| - def _AddRenamingSetter(self, attr, html_name):
|
| - self._members_emitter.Emit(
|
| - '\n void set $HTML_NAME($TYPE value)'
|
| - ' native "$(THIS).$NAME = value;";\n',
|
| - HTML_NAME=html_name,
|
| - NAME=attr.id,
|
| - TYPE=self._NarrowInputType(attr.type.id),
|
| - THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
|
| -
|
| - def AddOperation(self, info):
|
| - """
|
| - Arguments:
|
| - info: An OperationInfo object.
|
| - """
|
| - html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
|
| - if not html_name:
|
| - return
|
| -
|
| - maybe_return_document = self._shared.MaybeReturnDocument(info.type_name)
|
| -
|
| - # Do we need a native body?
|
| - if (self._interface.id == 'Document' or # Need alternate 'this'
|
| - html_name != info.name or # renamed operation
|
| - maybe_return_document): # need to wrap value
|
| - # For example: use window.document instead of his.parentNode.
|
| - return_type = self._NarrowOutputType(info.type_name)
|
| -
|
| - operation_emitter = self._members_emitter.Emit('$!SCOPE',
|
| - THIS=('this.parentNode' if self._interface.id == 'Document'
|
| - else 'this'),
|
| - TYPE=return_type,
|
| - HTML_NAME=html_name,
|
| - NAME=info.name,
|
| - RETURN='' if return_type == 'void' else 'return ',
|
| - PARAMNAMES=info.ParametersAsArgumentList(),
|
| - PARAMS=info.ParametersImplementationDeclaration(
|
| - lambda type_name: self._NarrowInputType(type_name)))
|
| -
|
| - if maybe_return_document:
|
| - assert len(info.overloads) == 1
|
| - operation_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE $(HTML_NAME)($PARAMS) => '
|
| - '_FixHtmlDocumentReference(_$(HTML_NAME)($PARAMNAMES));\n'
|
| - '\n'
|
| - ' _EventTargetImpl _$(HTML_NAME)($PARAMS)'
|
| - ' native "return $(THIS).$NAME($PARAMNAMES);";\n')
|
| - else:
|
| - operation_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE $(HTML_NAME)($PARAMS)'
|
| - ' native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n')
|
| - else:
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE $NAME($PARAMS) native;\n',
|
| - TYPE=self._NarrowOutputType(info.type_name),
|
| - NAME=info.name,
|
| - PARAMS=info.ParametersImplementationDeclaration(
|
| - lambda type_name: self._NarrowInputType(type_name)))
|
| -
|
| - def AddEventAttributes(self, event_attrs):
|
| - event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
|
| - events_class = '_' + self._interface.id + 'EventsImpl'
|
| - events_interface = self._interface.id + 'Events'
|
| - self._EmitEventGetter(events_class)
|
| -
|
| - self._shared._event_classes.add(self._interface.id)
|
| -
|
| - parent_event_class = self._shared.GetParentEventsClass(self._interface)
|
| -
|
| - # TODO(jacobr): specify the type of _ptr as EventTarget
|
| - events_members = self._dart_code.Emit(
|
| - '\n'
|
| - 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
|
| - ' $CLASSNAME(_ptr) : super(_ptr);\n'
|
| - '$!MEMBERS}\n',
|
| - CLASSNAME=events_class,
|
| - INTERFACE=events_interface,
|
| - SUPER='_' + parent_event_class + 'Impl')
|
| -
|
| - for event_name in event_attrs:
|
| - if event_name in _html_event_names:
|
| - events_members.Emit(
|
| - "\n"
|
| - " EventListenerList get $NAME() => _get('$RAWNAME');\n",
|
| - RAWNAME=event_name,
|
| - NAME=_html_event_names[event_name])
|
| - else:
|
| - raise Exception('No known html even name for event: ' + event_name)
|
| -
|
| - def _EmitEventGetter(self, events_class):
|
| - self._members_emitter.Emit(
|
| - '\n $TYPE get on() =>\n new $TYPE($EVENTTARGET);\n',
|
| - TYPE=events_class,
|
| - EVENTTARGET='_jsDocument' if self._interface.id == 'Document'
|
| - else 'this')
|
| -
|
| -# ------------------------------------------------------------------------------
|
| -
|
| -class HtmlFrogSystem(HtmlSystem):
|
| -
|
| - def __init__(self, templates, database, emitters, output_dir, generator):
|
| - super(HtmlFrogSystem, self).__init__(
|
| - templates, database, emitters, output_dir, generator)
|
| - self._dart_frog_file_paths = []
|
| -
|
| -
|
| - def InterfaceGenerator(self,
|
| - interface,
|
| - common_prefix,
|
| - super_interface_name,
|
| - source_filter):
|
| - """."""
|
| - template_file = 'impl_%s.darttemplate' % interface.id
|
| - template = self._templates.TryLoad(template_file)
|
| - if not template:
|
| - template = self._templates.Load('frog_impl.darttemplate')
|
| -
|
| - dart_code = self._ImplFileEmitter(interface.id)
|
| - return HtmlFrogClassGenerator(self, interface, template,
|
| - super_interface_name, dart_code, self._shared)
|
| -
|
| - def GenerateLibraries(self, lib_dir):
|
| - self._GenerateLibFile(
|
| - 'html_frog.darttemplate',
|
| - os.path.join(lib_dir, 'html_frog.dart'),
|
| - (self._interface_system._dart_interface_file_paths +
|
| - self._interface_system._dart_callback_file_paths +
|
| - self._dart_frog_file_paths))
|
| -
|
| - def Finish(self):
|
| - pass
|
| -
|
| - def _ImplFileEmitter(self, name):
|
| - """Returns the file emitter of the Frog implementation file."""
|
| - # TODO(jmesserly): is this the right path
|
| - path = os.path.join(self._output_dir, 'html', 'frog', '%s.dart' % name)
|
| - self._dart_frog_file_paths.append(path)
|
| - return self._emitters.FileEmitter(path)
|
| -
|
| -# -----------------------------------------------------------------------------
|
| -
|
| -class HtmlDartiumSystem(HtmlSystem):
|
| -
|
| - def __init__(self, templates, database, emitters, output_dir, generator):
|
| - """Prepared for generating wrapping implementation.
|
| -
|
| - - Creates emitter for Dart code.
|
| - """
|
| - super(HtmlDartiumSystem, self).__init__(
|
| - templates, database, emitters, output_dir, generator)
|
| - self._shared = HtmlSystemShared(database, generator)
|
| - self._dart_dartium_file_paths = []
|
| - self._wrap_cases = []
|
| -
|
| - def InterfaceGenerator(self,
|
| - interface,
|
| - common_prefix,
|
| - super_interface_name,
|
| - source_filter):
|
| - """."""
|
| - template_file = 'impl_%s.darttemplate' % interface.id
|
| - template = self._templates.TryLoad(template_file)
|
| - # TODO(jacobr): change this name as it is confusing.
|
| - if not template:
|
| - template = self._templates.Load('frog_impl.darttemplate')
|
| -
|
| - dart_code = self._ImplFileEmitter(interface.id)
|
| - return HtmlDartiumInterfaceGenerator(self, interface, template,
|
| - super_interface_name, dart_code, self._BaseDefines(interface),
|
| - self._shared)
|
| -
|
| - def _ImplFileEmitter(self, name):
|
| - """Returns the file emitter of the Dartium implementation file."""
|
| - path = os.path.join(self._output_dir, 'html', 'dartium', '%s.dart' % name)
|
| - self._dart_dartium_file_paths.append(path)
|
| - return self._emitters.FileEmitter(path);
|
| -
|
| - def ProcessCallback(self, interface, info):
|
| - pass
|
| -
|
| - def GenerateLibraries(self, lib_dir):
|
| - # Library generated for implementation.
|
| - self._GenerateLibFile(
|
| - 'html_dartium.darttemplate',
|
| - os.path.join(lib_dir, 'html_dartium.dart'),
|
| - (self._interface_system._dart_interface_file_paths +
|
| - self._interface_system._dart_callback_file_paths +
|
| - self._dart_dartium_file_paths
|
| - ),
|
| - WRAPCASES='\n'.join(self._wrap_cases))
|
| -
|
| - def Finish(self):
|
| - pass
|
| -
|
| -# ------------------------------------------------------------------------------
|
| -
|
| -# TODO(jacobr): there is far too much duplicated code between these bindings
|
| -# and the Frog bindings. A larger scale refactoring needs to be performed to
|
| -# reduce the duplicated logic.
|
| -class HtmlDartiumInterfaceGenerator(object):
|
| - """Generates a wrapper based implementation fo the HTML library that works
|
| - on Dartium. This is not intended to be the final solution for implementing
|
| - dart:html on Dartium. Eventually we should generate direct wrapperless
|
| - dart:html bindings that work on dartium."""
|
| -
|
| - def __init__(self, system, interface, template, super_interface, dart_code,
|
| - base_members, shared):
|
| - """Generates Dart wrapper code for the given interface.
|
| -
|
| - Args:
|
| - system: system that is executing this generator.
|
| - template: template that output is generated into.
|
| - 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.
|
| - super_interface: A string or None, the name of the common interface that
|
| - this interface implements, if any.
|
| - dart_code: an Emitter for the file containing the Dart implementation
|
| - class.
|
| - base_members: a set of names of members defined in a base class. This is
|
| - used to avoid static member 'overriding' in the generated Dart code.
|
| - shared: functionaly shared across all Html generators.
|
| - """
|
| - self._system = system
|
| - self._interface = interface
|
| - self._super_interface = super_interface
|
| - self._dart_code = dart_code
|
| - self._base_members = base_members
|
| - self._current_secondary_parent = None
|
| - self._shared = shared
|
| - self._template = template
|
| -
|
| - def DomObjectName(self):
|
| - return '_documentPtr' if self._interface.id == 'Document' else '_ptr'
|
| -
|
| - # TODO(jacobr): these 3 methods are duplicated.
|
| - def _NarrowToImplementationType(self, type_name):
|
| - # TODO(sra): Move into the 'system' and cache the result.
|
| - if type_name == 'EventListener':
|
| - # Callbacks are typedef functions so don't have a class.
|
| - return type_name
|
| - if self._system._database.HasInterface(type_name):
|
| - interface = self._system._database.GetInterface(type_name)
|
| - if RecognizeCallback(interface):
|
| - # Callbacks are typedef functions so don't have a class.
|
| - return type_name
|
| - else:
|
| - return self._ImplClassName(type_name)
|
| - return type_name
|
| -
|
| - def _NarrowInputType(self, type_name):
|
| - return self._NarrowToImplementationType(type_name)
|
| -
|
| - def _NarrowOutputType(self, type_name):
|
| - return self._NarrowToImplementationType(type_name)
|
| -
|
| - def StartInterface(self):
|
| -
|
| - interface = self._interface
|
| - interface_name = interface.id
|
| - self._class_name = self._ImplClassName(interface_name)
|
| -
|
| - base = None
|
| - if interface.parents:
|
| - supertype = interface.parents[0].type.id
|
| - if not IsDartListType(supertype):
|
| - base = self._ImplClassName(supertype)
|
| - if IsDartCollectionType(supertype):
|
| - # List methods are injected in AddIndexer.
|
| - pass
|
| - else:
|
| - base = self._ImplClassName(supertype)
|
| -
|
| - # TODO(jacobr): this is fragile. There isn't a guarantee that dart:dom
|
| - # will continue to exactly match the IDL names.
|
| - dom_name = interface.javascript_binding_name
|
| - # We hard code the cases for these classes
|
| - if dom_name != 'HTMLHtmlElement' and dom_name != 'Document':
|
| - self._system._wrap_cases.append(
|
| - ' case "%s": return new %s._wrap(domObject);' %
|
| - (dom_name, self._class_name))
|
| -
|
| - extends = ' extends ' + base if base else ' extends _DOMTypeBase'
|
| -
|
| - # TODO: Include all implemented interfaces, including other Lists.
|
| - implements = [interface_name]
|
| - element_type = MaybeTypedArrayElementType(self._interface)
|
| - if element_type:
|
| - implements.append('List<' + DartType(element_type) + '>')
|
| - implements_str = ', '.join(implements)
|
| -
|
| - (self._members_emitter,
|
| - self._top_level_emitter) = self._dart_code.Emit(
|
| - self._template + '$!TOP_LEVEL',
|
| - #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
|
| - #$!MEMBERS
|
| - #}
|
| - NATIVESPEC='', # hack to make reusing the same templates work.
|
| - CLASSNAME=self._class_name,
|
| - EXTENDS=extends,
|
| - IMPLEMENTS=' implements ' + implements_str)
|
| -
|
| - # Document requires a custom wrapper.
|
| - if dom_name != 'Document':
|
| - self._members_emitter.Emit(
|
| - ' $(CLASSNAME)._wrap(ptr) : super._wrap(ptr);\n',
|
| - CLASSNAME=self._class_name)
|
| -
|
| - # Emit a factory provider class for the constructor.
|
| - constructor_info = AnalyzeConstructor(interface)
|
| - if constructor_info:
|
| - self._EmitFactoryProvider(interface_name, constructor_info)
|
| -
|
| - emit_events, events = self._shared.GetEventAttributes(self._interface)
|
| - if not emit_events:
|
| - return
|
| - elif events:
|
| - self.AddEventAttributes(events)
|
| - else:
|
| - parent_events_class = self._shared.GetParentEventsClass(self._interface)
|
| - self._EmitEventGetter('_' + parent_events_class + 'Impl')
|
| -
|
| - def _EmitFactoryProvider(self, interface_name, constructor_info):
|
| - template_file = 'factoryprovider_%s.darttemplate' % interface_name
|
| - template = self._system._templates.TryLoad(template_file)
|
| - if not template:
|
| - template = self._system._templates.Load('factoryprovider.darttemplate')
|
| -
|
| - factory_provider = '_' + interface_name + 'FactoryProvider'
|
| - emitter = self._system._ImplFileEmitter(factory_provider)
|
| - emitter.Emit(
|
| - template,
|
| - FACTORYPROVIDER=factory_provider,
|
| - CONSTRUCTOR=interface_name,
|
| - PARAMETERS=constructor_info.ParametersImplementationDeclaration(),
|
| - NAMED_CONSTRUCTOR=constructor_info.name or interface_name,
|
| - ARGUMENTS=self._UnwrappedParameters(constructor_info,
|
| - len(constructor_info.arg_infos)))
|
| -
|
| - def _UnwrappedParameters(self, operation_info, length):
|
| - """Returns string for an argument list that unwraps first |length|
|
| - parameters."""
|
| - def UnwrapArgInfo(arg_info):
|
| - (name, type, value) = arg_info
|
| - # TODO(sra): Type dependent unwrapping.
|
| - return '_unwrap(%s)' % name
|
| -
|
| - return ', '.join(map(UnwrapArgInfo, operation_info.arg_infos[:length]))
|
| -
|
| - def _BaseClassName(self, interface):
|
| - if not interface.parents:
|
| - return '_DOMTypeBase'
|
| -
|
| - supertype = DartType(interface.parents[0].type.id)
|
| -
|
| - if IsDartListType(supertype) or IsDartCollectionType(supertype):
|
| - return 'DOMWrapperBase'
|
| -
|
| - if supertype == 'EventTarget':
|
| - # Most implementors of EventTarget specify the EventListener operations
|
| - # again. If the operations are not specified, try to inherit from the
|
| - # EventTarget implementation.
|
| - #
|
| - # Applies to MessagePort.
|
| - if not [op for op in interface.operations if op.id == 'addEventListener']:
|
| - return self._ImplClassName(supertype)
|
| - return 'DOMWrapperBase'
|
| -
|
| - return self._ImplClassName(supertype)
|
| -
|
| - def _ImplClassName(self, type_name):
|
| - return self._shared._ImplClassName(type_name)
|
| -
|
| - def FinishInterface(self):
|
| - """."""
|
| - pass
|
| -
|
| - def AddConstant(self, constant):
|
| - # Constants are already defined on the interface.
|
| - pass
|
| -
|
| - def _MethodName(self, prefix, name):
|
| - method_name = prefix + name
|
| - if name in self._base_members: # Avoid illegal Dart 'static override'.
|
| - method_name = method_name + '_' + self._interface.id
|
| - return method_name
|
| -
|
| - def AddAttribute(self, getter, setter):
|
| - dom_name = DartDomNameOfAttribute(getter or setter)
|
| - html_getter_name = self._shared.RenameInHtmlLibrary(
|
| - self._interface, dom_name, 'get:')
|
| - html_setter_name = self._shared.RenameInHtmlLibrary(
|
| - self._interface, dom_name, 'set:')
|
| -
|
| - if getter and html_getter_name:
|
| - self._AddGetter(getter, html_getter_name)
|
| - if setter and html_setter_name:
|
| - self._AddSetter(setter, html_setter_name)
|
| -
|
| - def _AddGetter(self, attr, html_name):
|
| - if self._shared.MaybeReturnDocument(attr.type.id):
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE get $(HTML_NAME)() => '
|
| - '_FixHtmlDocumentReference(_wrap($(THIS).$DOM_NAME));\n',
|
| - HTML_NAME=html_name,
|
| - DOM_NAME=DartDomNameOfAttribute(attr),
|
| - TYPE=DartType(attr.type.id),
|
| - THIS=self.DomObjectName())
|
| - else:
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE get $(HTML_NAME)() => _wrap($(THIS).$DOM_NAME);\n',
|
| - HTML_NAME=html_name,
|
| - DOM_NAME=DartDomNameOfAttribute(attr),
|
| - TYPE=DartType(attr.type.id),
|
| - THIS=self.DomObjectName())
|
| -
|
| - def _AddSetter(self, attr, html_name):
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' void set $(HTML_NAME)($TYPE value) { '
|
| - '$(THIS).$DOM_NAME = _unwrap(value); }\n',
|
| - HTML_NAME=html_name,
|
| - DOM_NAME=DartDomNameOfAttribute(attr),
|
| - TYPE=DartType(attr.type.id),
|
| - THIS=self.DomObjectName())
|
| -
|
| - def AddSecondaryAttribute(self, interface, getter, setter):
|
| - self._SecondaryContext(interface)
|
| - self.AddAttribute(getter, setter)
|
| -
|
| - def AddSecondaryOperation(self, interface, info):
|
| - self._SecondaryContext(interface)
|
| - self.AddOperation(info)
|
| -
|
| - def AddEventAttributes(self, event_attrs):
|
| - event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
|
| - events_class = '_' + self._interface.id + 'EventsImpl'
|
| - events_interface = self._interface.id + 'Events'
|
| - self._EmitEventGetter(events_class)
|
| -
|
| - self._shared._event_classes.add(self._interface.id)
|
| -
|
| - parent_event_class = self._shared.GetParentEventsClass(self._interface)
|
| -
|
| - # TODO(jacobr): specify the type of _ptr as EventTarget
|
| - events_members = self._dart_code.Emit(
|
| - '\n'
|
| - 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
|
| - ' $CLASSNAME(_ptr) : super(_ptr);\n'
|
| - '$!MEMBERS}\n',
|
| - CLASSNAME=events_class,
|
| - INTERFACE=events_interface,
|
| - SUPER='_' + parent_event_class + 'Impl')
|
| -
|
| - for event_name in event_attrs:
|
| - if event_name in _html_event_names:
|
| - events_members.Emit(
|
| - "\n"
|
| - " EventListenerList get $NAME() => _get('$RAWNAME');\n",
|
| - RAWNAME=event_name,
|
| - NAME=_html_event_names[event_name])
|
| - else:
|
| - raise Exception('No known html even name for event: ' + event_name)
|
| -
|
| - def _EmitEventGetter(self, events_class):
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE get on() {\n'
|
| - ' if (_on == null) _on = new $TYPE($EVENTTARGET);\n'
|
| - ' return _on;\n'
|
| - ' }\n',
|
| - TYPE=events_class,
|
| - EVENTTARGET='_wrappedDocumentPtr' if self._interface.id == 'Document'
|
| - else 'this')
|
| -
|
| - 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)
|
| -
|
| - # TODO(jacobr): change this to more directly match the frog version.
|
| - 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
|
| - # get 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; }
|
| - #
|
| - if self._HasNativeIndexGetter(self._interface):
|
| - self._EmitNativeIndexGetter(self._interface, element_type)
|
| - else:
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE operator[](int index) => _wrap($(THIS)[index]);\n'
|
| - '\n',
|
| - THIS=self.DomObjectName(),
|
| - TYPE=DartType(element_type))
|
| -
|
| - if self._HasNativeIndexSetter(self._interface):
|
| - self._EmitNativeIndexSetter(self._interface, element_type)
|
| - else:
|
| - # The HTML library implementation of NodeList has a custom indexed setter
|
| - # implementation that uses the parent node the NodeList is associated
|
| - # with if one is available.
|
| - if self._interface.id != 'NodeList':
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' void operator[]=(int index, $TYPE value) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
|
| - ' }\n',
|
| - TYPE=DartType(element_type))
|
| -
|
| - # The list interface for this class is manually generated.
|
| - if self._interface.id == 'NodeList':
|
| - return
|
| -
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' void add($TYPE value) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot add to immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void addLast($TYPE value) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot add to immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void addAll(Collection<$TYPE> collection) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot add to immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void sort(int compare($TYPE a, $TYPE b)) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot sort immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void copyFrom(List<Object> src, int srcStart, '
|
| - 'int dstStart, int count) {\n'
|
| - ' throw new UnsupportedOperationException("This object is immutable.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' int indexOf($TYPE element, [int start = 0]) {\n'
|
| - ' return _Lists.indexOf(this, element, start, this.length);\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' int lastIndexOf($TYPE element, [int start = null]) {\n'
|
| - ' if (start === null) start = length - 1;\n'
|
| - ' return _Lists.lastIndexOf(this, element, start);\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' int clear() {\n'
|
| - ' throw new UnsupportedOperationException("Cannot clear immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' $TYPE removeLast() {\n'
|
| - ' throw new UnsupportedOperationException("Cannot removeLast on immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' $TYPE last() {\n'
|
| - ' return this[length - 1];\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void forEach(void f($TYPE element)) {\n'
|
| - ' _Collections.forEach(this, f);\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' Collection map(f($TYPE element)) {\n'
|
| - ' return _Collections.map(this, [], f);\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' Collection<$TYPE> filter(bool f($TYPE element)) {\n'
|
| - ' return _Collections.filter(this, new List<$TYPE>(), f);\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' bool every(bool f($TYPE element)) {\n'
|
| - ' return _Collections.every(this, f);\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' bool some(bool f($TYPE element)) {\n'
|
| - ' return _Collections.some(this, f);\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void setRange(int start, int length, List<$TYPE> from, [int startFrom]) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot setRange on immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void removeRange(int start, int length) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot removeRange on immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' void insertRange(int start, int length, [$TYPE initialValue]) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot insertRange on immutable List.");\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' List<$TYPE> getRange(int start, int length) {\n'
|
| - ' throw new NotImplementedException();\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' bool isEmpty() {\n'
|
| - ' return length == 0;\n'
|
| - ' }\n'
|
| - '\n'
|
| - ' Iterator<$TYPE> iterator() {\n'
|
| - ' return new _FixedSizeListIterator<$TYPE>(this);\n'
|
| - ' }\n',
|
| - TYPE=DartType(element_type))
|
| -
|
| - def _HasNativeIndexGetter(self, interface):
|
| - return ('HasIndexGetter' in interface.ext_attrs or
|
| - 'HasNumericIndexGetter' in interface.ext_attrs)
|
| -
|
| - def _EmitNativeIndexGetter(self, interface, element_type):
|
| - method_name = '_index'
|
| - self._members_emitter.Emit(
|
| - '\n $TYPE operator[](int index) => _wrap($(THIS)[index]);\n',
|
| - TYPE=DartType(element_type),
|
| - THIS=self.DomObjectName(),
|
| - METHOD=method_name)
|
| -
|
| - def _HasNativeIndexSetter(self, interface):
|
| - return 'HasCustomIndexSetter' in interface.ext_attrs
|
| -
|
| - def _EmitNativeIndexSetter(self, interface, element_type):
|
| - method_name = '_set_index'
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' void operator[]=(int index, $TYPE value) {\n'
|
| - ' return $(THIS)[index] = _unwrap(value);\n'
|
| - ' }\n',
|
| - THIS=self.DomObjectName(),
|
| - TYPE=DartType(element_type),
|
| - METHOD=method_name)
|
| -
|
| - def AddOperation(self, info):
|
| - """
|
| - Arguments:
|
| - info: An OperationInfo object.
|
| - """
|
| - html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
|
| -
|
| - if not html_name:
|
| - return
|
| -
|
| - body = self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE $HTML_NAME($PARAMS) {\n'
|
| - '$!BODY'
|
| - ' }\n',
|
| - TYPE=info.type_name,
|
| - HTML_NAME=html_name,
|
| - PARAMS=info.ParametersImplementationDeclaration())
|
| -
|
| - # Process in order of ascending number of arguments to ensure missing
|
| - # optional arguments are processed early.
|
| - overloads = sorted(info.overloads,
|
| - key=lambda overload: len(overload.arguments))
|
| - self._native_version = 0
|
| - fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads)
|
| - if fallthrough:
|
| - body.Emit(' throw "Incorrect number or type of arguments";\n');
|
| -
|
| - def GenerateSingleOperation(self, emitter, info, indent, operation):
|
| - """Generates a call to a single operation.
|
| -
|
| - Arguments:
|
| - emitter: an Emitter for the body of a block of code.
|
| - info: the compound information about the operation and its overloads.
|
| - indent: an indentation string for generated code.
|
| - operation: the IDLOperation to call.
|
| - """
|
| - argument_expressions = self._UnwrappedParameters(
|
| - info,
|
| - len(operation.arguments)) # Just the parameters this far.
|
| -
|
| - if info.type_name != 'void':
|
| - # We could place the logic for handling Document directly in _wrap
|
| - # but we chose to place it here so that bugs in the wrapper and
|
| - # wrapperless implementations are more consistent.
|
| - if self._shared.MaybeReturnDocument(info.type_name):
|
| - emitter.Emit('$(INDENT)return _FixHtmlDocumentReference('
|
| - '_wrap($(THIS).$NAME($ARGS)));\n',
|
| - INDENT=indent,
|
| - THIS=self.DomObjectName(),
|
| - NAME=info.name,
|
| - ARGS=argument_expressions)
|
| - else:
|
| - emitter.Emit('$(INDENT)return _wrap($(THIS).$NAME($ARGS));\n',
|
| - INDENT=indent,
|
| - THIS=self.DomObjectName(),
|
| - NAME=info.name,
|
| - ARGS=argument_expressions)
|
| - else:
|
| - emitter.Emit('$(INDENT)$(THIS).$NAME($ARGS);\n'
|
| - '$(INDENT)return;\n',
|
| - INDENT=indent,
|
| - THIS=self.DomObjectName(),
|
| - NAME=info.name,
|
| - ARGS=argument_expressions)
|
| -
|
| - def GenerateDispatch(self, emitter, info, indent, position, overloads):
|
| - """Generates a dispatch to one of the overloads.
|
| -
|
| - Arguments:
|
| - emitter: an Emitter for the body of a block of code.
|
| - info: the compound information about the operation and its overloads.
|
| - indent: an indentation string for generated code.
|
| - position: the index of the parameter to dispatch on.
|
| - overloads: a list of the remaining IDLOperations to dispatch.
|
| -
|
| - Returns True if the dispatch can fall through on failure, False if the code
|
| - always dispatches.
|
| - """
|
| -
|
| - def NullCheck(name):
|
| - return '%s === null' % name
|
| -
|
| - def TypeCheck(name, type):
|
| - return '%s is %s' % (name, type)
|
| -
|
| - if position == len(info.arg_infos):
|
| - if len(overloads) > 1:
|
| - raise Exception('Duplicate operations ' + str(overloads))
|
| - operation = overloads[0]
|
| - self.GenerateSingleOperation(emitter, info, indent, operation)
|
| - return False
|
| -
|
| - # FIXME: Consider a simpler dispatch that iterates over the
|
| - # overloads and generates an overload specific check. Revisit
|
| - # when we move to named optional arguments.
|
| -
|
| - # Partition the overloads to divide and conquer on the dispatch.
|
| - positive = []
|
| - negative = []
|
| - first_overload = overloads[0]
|
| - (param_name, param_type, param_default) = info.arg_infos[position]
|
| -
|
| - if position < len(first_overload.arguments):
|
| - # FIXME: This will not work if the second overload has a more
|
| - # precise type than the first. E.g.,
|
| - # void foo(Node x);
|
| - # void foo(Element x);
|
| - type = DartType(first_overload.arguments[position].type.id)
|
| - test = TypeCheck(param_name, type)
|
| - pred = lambda op: (len(op.arguments) > position and
|
| - DartType(op.arguments[position].type.id) == type)
|
| - else:
|
| - type = None
|
| - test = NullCheck(param_name)
|
| - pred = lambda op: position >= len(op.arguments)
|
| -
|
| - for overload in overloads:
|
| - if pred(overload):
|
| - positive.append(overload)
|
| - else:
|
| - negative.append(overload)
|
| -
|
| - if positive and negative:
|
| - (true_code, false_code) = emitter.Emit(
|
| - '$(INDENT)if ($COND) {\n'
|
| - '$!TRUE'
|
| - '$(INDENT)} else {\n'
|
| - '$!FALSE'
|
| - '$(INDENT)}\n',
|
| - COND=test, INDENT=indent)
|
| - fallthrough1 = self.GenerateDispatch(
|
| - true_code, info, indent + ' ', position + 1, positive)
|
| - fallthrough2 = self.GenerateDispatch(
|
| - false_code, info, indent + ' ', position, negative)
|
| - return fallthrough1 or fallthrough2
|
| -
|
| - if negative:
|
| - raise Exception('Internal error, must be all positive')
|
| -
|
| - # All overloads require the same test. Do we bother?
|
| -
|
| - # If the test is the same as the method's formal parameter then checked mode
|
| - # will have done the test already. (It could be null too but we ignore that
|
| - # case since all the overload behave the same and we don't know which types
|
| - # in the IDL are not nullable.)
|
| - if type == param_type:
|
| - return self.GenerateDispatch(
|
| - emitter, info, indent, position + 1, positive)
|
| -
|
| - # Otherwise the overloads have the same type but the type is a substype of
|
| - # the method's synthesized formal parameter. e.g we have overloads f(X) and
|
| - # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The
|
| - # dispatch has removed f(X), leaving only f(Y), but there is no guarantee
|
| - # that Y = Z-X, so we need to check for Y.
|
| - true_code = emitter.Emit(
|
| - '$(INDENT)if ($COND) {\n'
|
| - '$!TRUE'
|
| - '$(INDENT)}\n',
|
| - COND=test, INDENT=indent)
|
| - self.GenerateDispatch(
|
| - true_code, info, indent + ' ', position + 1, positive)
|
| - return True
|
|
|