Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: client/dom/scripts/systemhtml.py

Issue 9537001: Generate dart:html bindings for Dartium as well as Frog. All unittests now pass (or are disabled fo… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
3 # for details. All rights reserved. Use of this source code is governed by a 3 # for details. All rights reserved. Use of this source code is governed by a
4 # BSD-style license that can be found in the LICENSE file. 4 # BSD-style license that can be found in the LICENSE file.
5 5
6 """This module provides shared functionality for the system to generate 6 """This module provides shared functionality for the system to generate
7 Dart:html APIs from the IDL database.""" 7 Dart:html APIs from the IDL database."""
8 8
9 import os 9 import os
10 from generator import * 10 from generator import *
11 from systembase import * 11 from systembase import *
12 from systemfrog import * 12 from systemfrog import *
13 from systeminterface import * 13 from systeminterface import *
sra1 2012/02/29 23:11:55 Are you using this import? You could comment it o
Jacob 2012/03/01 00:40:44 Done.
14 from systemwrapping import *
sra1 2012/02/29 23:11:55 Are you using this import?
Jacob 2012/03/01 00:40:44 Done.
14 15
15 # Members from the standard dom that should not be exposed publicly in dart:html 16 # Members from the standard dom that should not be exposed publicly in dart:html
16 # but need to be exposed internally to implement dart:html on top of a standard 17 # but need to be exposed internally to implement dart:html on top of a standard
17 # browser. 18 # browser.
18 _private_html_members = { 19 _private_html_members = set([
19 'Element': set(['clientLeft', 'clientTop', 'clientWidth', 'clientHeight', 20 'Element.clientLeft',
20 'offsetLeft', 'offsetTop', 'offsetWidth', 'offsetHeight', 21 'Element.clientTop',
21 'scrollLeft', 'scrollTop', 'scrollWidth', 'scrollHeight', 22 'Element.clientWidth',
22 'childElementCount', 'firstElementChild', 'hasAttribute', 23 'Element.clientHeight',
23 'getAttribute', 'removeAttribute', 'setAttribute', 'className', 24 'Element.offsetLeft',
24 'children']), 25 'Element.offsetTop',
25 'Node' : set(['appendChild', 'removeChild', 'replaceChild', 'attributes', 26 'Element.offsetWidth',
26 'childNodes']), 27 'Element.offsetHeight',
27 # TODO(jacobr): other direct translate methods on node such as 28 'Element.scrollLeft',
28 # textContext->text 29 'Element.scrollTop',
29 'Document': set(['createElement', 'createEvent']), 30 'Element.scrollWidth',
30 'Window': set(['getComputedStyle']), 31 'Element.scrollHeight',
31 'EventTarget': set(['removeEventListener', 'addEventListener', 32 'Element.childElementCount',
32 'dispatchEvent']), 33 'Element.firstElementChild',
33 'Event': set(['initEvent', 'target', 'srcElement', 'currentTarget']) 34 'Element.hasAttribute',
34 } 35 'Element.getAttribute',
36 'Element.removeAttribute',
37 'Element.setAttribute',
38 'Element.className',
39 'Element.children',
40 'Element.querySelectorAll',
41 'Document.querySelectorAll',
42 'Element.getBoundingClientRect',
43 'Element.getClientRects',
44 'Node.appendChild',
45 'Node.removeChild',
46 'Node.replaceChild',
47 'Node.attributes',
48 'Node.childNodes',
49 'Document.createElement',
50 'Document.createEvent',
51 'Document.createTextNode',
52 'Document.createTouchList',
53 'Window.getComputedStyle',
54 'EventTarget.removeEventListener',
55 'EventTarget.addEventListener',
56 'EventTarget.dispatchEvent',
57 'Event.initEvent',
58 'MouseEvent.initMouseEvent',
59 ])
35 60
36 # Members from the standard dom that exist in the dart:html library with 61 # Members from the standard dom that exist in the dart:html library with
37 # identical functionality but with cleaner names. 62 # identical functionality but with cleaner names.
38 html_library_renames = { 63 _html_library_renames = {
39 'Document.createTextNode': 'Text.Text', 64 'Document.defaultView': 'window',
40 'Document.get:defaultView': 'Document.get:window', 65 'DocumentFragment.querySelector': 'query',
41 'DocumentFragment.querySelector': 'Element.query', 66 'Element.querySelector': 'query',
42 'Element.querySelector': 'Element.query', 67 'Element.webkitMatchesSelector' : 'matchesSelector',
43 'Document.querySelector': 'Element.query', 68 'Element.scrollIntoViewIfNeeded': 'scrollIntoView',
44 'DocumentFragment.querySelectorAll': 'Element.queryAll', 69 'Document.querySelector': 'query',
45 'DocumentFragment.querySelectorAll': 'Element.queryAll', 70 'DocumentFragment.querySelectorAll': 'queryAll',
46 'Element.querySelectorAll': 'Element.queryAll', 71 'DocumentFragment.querySelectorAll': 'queryAll',
47 'Element.scrollIntoViewIfNeeded': 'Element.scrollIntoView', 72 'Node.cloneNode': 'clone',
48 'Node.cloneNode': 'Node.clone', 73 'Node.nextSibling': 'nextNode',
49 'Node.get:nextSibling': 'Node.get:nextNode', 74 'Node.ownerDocument': 'document',
50 'Node.get:ownerDocument': 'Node.get:document', 75 'Node.parentNode': 'parent',
51 'Node.get:parentNode': 'Node.get:parent', 76 'Node.previousSibling': 'previousNode',
52 'Node.get:previousSibling': 'Node.get:previousNode', 77 'Node.textContent': 'text',
53 } 78 }
54 79
80 #TODO(jacobr): inject annotations into the interfaces based on this table and
81 # on _html_library_renames.
82 _injected_doc_fragments = {
83 'Element.query': ' /** @domName querySelector, Document.getElementById */',
84 }
55 # Members and classes from the dom that should be removed completelly from 85 # Members and classes from the dom that should be removed completelly from
56 # dart:html. These could be expressed in the IDL instead but expressing this 86 # dart:html. These could be expressed in the IDL instead but expressing this
57 # as a simple table instead is more concise. 87 # as a simple table instead is more concise.
58 # TODO(jacobr): cleanup and augment this list. 88 # TODO(jacobr): cleanup and augment this list.
59 _html_library_remove = set([ 89 _html_library_remove = set([
60 'Window.get:document', # Removed as we have a custom implementation. 90 'Window.get:document', # Removed as we have a custom implementation.
61 'NodeList.item', 91 'NodeList.item',
62 "Attr.*", 92 "Attr.*",
63 # "BarProp.*", 93 # "BarProp.*",
64 # "BarInfo.*", 94 # "BarInfo.*",
(...skipping 12 matching lines...) Expand all
77 "Document.get:forms", 107 "Document.get:forms",
78 # "Document.get:selectedStylesheetSet", 108 # "Document.get:selectedStylesheetSet",
79 # "Document.set:selectedStylesheetSet", 109 # "Document.set:selectedStylesheetSet",
80 # "Document.get:preferredStylesheetSet", 110 # "Document.get:preferredStylesheetSet",
81 "Document.get:links", 111 "Document.get:links",
82 "Document.getElementsByTagName", 112 "Document.getElementsByTagName",
83 "Document.set:domain", 113 "Document.set:domain",
84 "Document.get:implementation", 114 "Document.get:implementation",
85 "Document.createAttributeNS", 115 "Document.createAttributeNS",
86 "Document.get:inputEncoding", 116 "Document.get:inputEncoding",
117 "Document.getElementById",
87 "Document.getElementsByClassName", 118 "Document.getElementsByClassName",
119 "Element.getElementsByClassName",
120 "Element.getElementsByTagNameNS",
121 "Element.getElementsByTagName",
88 "Document.get:compatMode", 122 "Document.get:compatMode",
89 "Document.importNode", 123 "Document.importNode",
90 "Document.evaluate", 124 "Document.evaluate",
91 "Document.get:images", 125 "Document.get:images",
92 "Document.querySelector", 126 "Document.querySelector",
93 "Document.createExpression", 127 "Document.createExpression",
94 "Document.getOverrideStyle", 128 "Document.getOverrideStyle",
95 "Document.get:xmlStandalone", 129 "Document.get:xmlStandalone",
96 "Document.set:xmlStandalone", 130 "Document.set:xmlStandalone",
97 "Document.createComment", 131 "Document.createComment",
(...skipping 25 matching lines...) Expand all
123 "DocumentType.*", 157 "DocumentType.*",
124 "Element.hasAttributeNS", 158 "Element.hasAttributeNS",
125 "Element.getAttributeNS", 159 "Element.getAttributeNS",
126 "Element.setAttributeNode", 160 "Element.setAttributeNode",
127 "Element.getAttributeNode", 161 "Element.getAttributeNode",
128 "Element.removeAttributeNode", 162 "Element.removeAttributeNode",
129 "Element.removeAttributeNS", 163 "Element.removeAttributeNS",
130 "Element.setAttributeNodeNS", 164 "Element.setAttributeNodeNS",
131 "Element.getAttributeNodeNS", 165 "Element.getAttributeNodeNS",
132 "Element.setAttributeNS", 166 "Element.setAttributeNS",
167 "BodyElement.text",
168 "AnchorElement.text",
169 "OptionElement.text",
170 "ScriptElement.text",
171 "TitleElement.text",
133 # "EventSource.get:url", 172 # "EventSource.get:url",
134 # TODO(jacobr): should these be removed? 173 # TODO(jacobr): should these be removed?
135 "Document.close", 174 "Document.close",
136 "Document.hasFocus", 175 "Document.hasFocus",
137 176
138 "Document.get:vlinkColor", 177 "Document.get:vlinkColor",
139 "Document.set:vlinkColor", 178 "Document.set:vlinkColor",
140 "Document.captureEvents", 179 "Document.captureEvents",
141 "Document.releaseEvents", 180 "Document.releaseEvents",
142 "Document.get:compatMode", 181 "Document.get:compatMode",
(...skipping 12 matching lines...) Expand all
155 "Document.get:alinkColor", 194 "Document.get:alinkColor",
156 "Document.set:alinkColor", 195 "Document.set:alinkColor",
157 "Document.get:embeds", 196 "Document.get:embeds",
158 "Document.open", 197 "Document.open",
159 "Document.clear", 198 "Document.clear",
160 "Document.get:scripts", 199 "Document.get:scripts",
161 "Document.writeln", 200 "Document.writeln",
162 "Document.get:linkColor", 201 "Document.get:linkColor",
163 "Document.set:linkColor", 202 "Document.set:linkColor",
164 "Element.get:itemRef", 203 "Element.get:itemRef",
165 "Element.set:className",
166 "Element.get:outerText", 204 "Element.get:outerText",
167 "Element.set:outerText", 205 "Element.set:outerText",
168 "Element.get:accessKey", 206 "Element.get:accessKey",
169 "Element.set:accessKey", 207 "Element.set:accessKey",
170 "Element.get:itemType", 208 "Element.get:itemType",
171 "Element.get:innerText", 209 "Element.get:innerText",
172 "Element.set:innerText", 210 "Element.set:innerText",
173 "Element.set:outerHTML", 211 "Element.set:outerHTML",
174 "Element.get:itemScope", 212 "Element.get:itemScope",
175 "Element.set:itemScope", 213 "Element.set:itemScope",
176 "Element.get:itemValue", 214 "Element.get:itemValue",
177 "Element.set:itemValue", 215 "Element.set:itemValue",
178 "Element.get:itemId", 216 "Element.get:itemId",
179 "Element.set:itemId", 217 "Element.set:itemId",
180 "Element.get:itemProp", 218 "Element.get:itemProp",
219 'Element.scrollIntoView',
181 "EmbedElement.getSVGDocument", 220 "EmbedElement.getSVGDocument",
182 "FormElement.get:elements", 221 "FormElement.get:elements",
183 "HTMLFrameElement.*", 222 "HTMLFrameElement.*",
184 "HTMLFrameSetElement.*", 223 "HTMLFrameSetElement.*",
185 "HTMLHtmlElement.get:version", 224 "HTMLHtmlElement.get:version",
186 "HTMLHtmlElement.set:version", 225 "HTMLHtmlElement.set:version",
187 # "IFrameElement.getSVGDocument", #TODO(jacobr): should this be removed 226 # "IFrameElement.getSVGDocument", #TODO(jacobr): should this be removed
188 "InputElement.get:dirName", 227 "InputElement.get:dirName",
189 "InputElement.set:dirName", 228 "InputElement.set:dirName",
190 "HTMLIsIndexElement.*", 229 "HTMLIsIndexElement.*",
191 "ObjectElement.getSVGDocument", 230 "ObjectElement.getSVGDocument",
192 "HTMLOptionsCollection.*", 231 "HTMLOptionsCollection.*",
193 "HTMLPropertiesCollection.*", 232 "HTMLPropertiesCollection.*",
194 "SelectElement.remove", 233 "SelectElement.remove",
195 "TextAreaElement.get:dirName", 234 "TextAreaElement.get:dirName",
196 "TextAreaElement.set:dirName", 235 "TextAreaElement.set:dirName",
197 "NamedNodeMap.*", 236 "NamedNodeMap.*",
198 "Node.isEqualNode", 237 "Node.isEqualNode",
199 "Node.get:TEXT_NODE", 238 "Node.get:TEXT_NODE",
200 "Node.hasAttributes", 239 "Node.hasAttributes",
201 "Node.get:DOCUMENT_TYPE_NODE", 240 "Node.get:DOCUMENT_TYPE_NODE",
202 "Node.get:DOCUMENT_POSITION_FOLLOWING", 241 "Node.get:DOCUMENT_POSITION_FOLLOWING",
203 "Node.get:childNodes",
204 "Node.lookupNamespaceURI", 242 "Node.lookupNamespaceURI",
205 "Node.get:ELEMENT_NODE", 243 "Node.get:ELEMENT_NODE",
206 "Node.get:namespaceURI", 244 "Node.get:namespaceURI",
207 "Node.get:DOCUMENT_FRAGMENT_NODE", 245 "Node.get:DOCUMENT_FRAGMENT_NODE",
208 "Node.get:localName", 246 "Node.get:localName",
209 "Node.dispatchEvent", 247 "Node.dispatchEvent",
210 "Node.isDefaultNamespace", 248 "Node.isDefaultNamespace",
211 "Node.compareDocumentPosition", 249 "Node.compareDocumentPosition",
212 "Node.get:baseURI", 250 "Node.get:baseURI",
213 "Node.isSameNode", 251 "Node.isSameNode",
214 "Node.get:DOCUMENT_POSITION_DISCONNECTED", 252 "Node.get:DOCUMENT_POSITION_DISCONNECTED",
215 "Node.get:DOCUMENT_NODE", 253 "Node.get:DOCUMENT_NODE",
216 "Node.get:DOCUMENT_POSITION_CONTAINS", 254 "Node.get:DOCUMENT_POSITION_CONTAINS",
217 "Node.get:COMMENT_NODE", 255 "Node.get:COMMENT_NODE",
218 "Node.get:ENTITY_REFERENCE_NODE", 256 "Node.get:ENTITY_REFERENCE_NODE",
219 "Node.isSupported", 257 "Node.isSupported",
220 "Node.get:firstChild", 258 "Node.get:firstChild",
221 "Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC", 259 "Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC",
222 "Node.get:lastChild", 260 "Node.get:lastChild",
223 "Node.get:attributes",
224 "Node.get:NOTATION_NODE", 261 "Node.get:NOTATION_NODE",
225 "Node.normalize", 262 "Node.normalize",
226 "Node.get:parentElement", 263 "Node.get:parentElement",
227 "Node.get:ATTRIBUTE_NODE", 264 "Node.get:ATTRIBUTE_NODE",
228 "Node.get:ENTITY_NODE", 265 "Node.get:ENTITY_NODE",
229 "Node.get:DOCUMENT_POSITION_CONTAINED_BY", 266 "Node.get:DOCUMENT_POSITION_CONTAINED_BY",
230 "Node.get:prefix", 267 "Node.get:prefix",
231 "Node.set:prefix", 268 "Node.set:prefix",
232 "Node.get:DOCUMENT_POSITION_PRECEDING", 269 "Node.get:DOCUMENT_POSITION_PRECEDING",
233 "Node.get:nodeType", 270 "Node.get:nodeType",
(...skipping 18 matching lines...) Expand all
252 'Window': ['DOMContentLoaded'] 289 'Window': ['DOMContentLoaded']
253 } 290 }
254 291
255 # These event names must be camel case when attaching event listeners 292 # These event names must be camel case when attaching event listeners
256 # using addEventListener even though the onEventName properties in the DOM for 293 # using addEventListener even though the onEventName properties in the DOM for
257 # them are not camel case. 294 # them are not camel case.
258 _on_attribute_to_event_name_mapping = { 295 _on_attribute_to_event_name_mapping = {
259 'webkitanimationend': 'webkitAnimationEnd', 296 'webkitanimationend': 'webkitAnimationEnd',
260 'webkitanimationiteration': 'webkitAnimationIteration', 297 'webkitanimationiteration': 'webkitAnimationIteration',
261 'webkitanimationstart': 'webkitAnimationStart', 298 'webkitanimationstart': 'webkitAnimationStart',
262 'webkitfullscreenchange': 'webkitFullScreenChange',
263 'webkitfullscreenerror': 'webkitFullScreenError',
264 'webkitspeechchange': 'webkitSpeechChange', 299 'webkitspeechchange': 'webkitSpeechChange',
265 'webkittransitionend': 'webkitTransitionEnd', 300 'webkittransitionend': 'webkitTransitionEnd',
266 } 301 }
267 302
268 # Mapping from raw event names to the pretty camelCase event names exposed as 303 # Mapping from raw event names to the pretty camelCase event names exposed as
269 # properties in dart:html. If the DOM exposes a new event name, you will need 304 # properties in dart:html. If the DOM exposes a new event name, you will need
270 # to add the lower case to camel case conversion for that event name here. 305 # to add the lower case to camel case conversion for that event name here.
271 _html_event_names = { 306 _html_event_names = {
272 'DOMContentLoaded': 'contentLoaded', 307 'DOMContentLoaded': 'contentLoaded',
273 'touchleave': 'touchLeave', 308 'touchleave': 'touchLeave',
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 'touchend': 'touchEnd', 391 'touchend': 'touchEnd',
357 'touchmove': 'touchMove', 392 'touchmove': 'touchMove',
358 'touchstart': 'touchStart', 393 'touchstart': 'touchStart',
359 'unload': 'unload', 394 'unload': 'unload',
360 'updateready': 'updateReady', 395 'updateready': 'updateReady',
361 'volumechange': 'volumeChange', 396 'volumechange': 'volumeChange',
362 'waiting': 'waiting', 397 'waiting': 'waiting',
363 'webkitAnimationEnd': 'animationEnd', 398 'webkitAnimationEnd': 'animationEnd',
364 'webkitAnimationIteration': 'animationIteration', 399 'webkitAnimationIteration': 'animationIteration',
365 'webkitAnimationStart': 'animationStart', 400 'webkitAnimationStart': 'animationStart',
366 'webkitFullScreenChange': 'fullScreenChange', 401 'webkitfullscreenchange': 'fullscreenChange',
367 'webkitFullScreenError': 'fullScreenError', 402 'webkitfullscreenerror': 'fullscreenError',
368 'webkitSpeechChange': 'speechChange', 403 'webkitSpeechChange': 'speechChange',
369 'webkitTransitionEnd': 'transitionEnd' 404 'webkitTransitionEnd': 'transitionEnd'
370 } 405 }
371 406
372 def _OnAttributeToEventName(on_method): 407 def _OnAttributeToEventName(on_method):
373 event_name = on_method.id[2:] 408 event_name = on_method.id[2:]
374 if event_name in _on_attribute_to_event_name_mapping: 409 if event_name in _on_attribute_to_event_name_mapping:
375 return _on_attribute_to_event_name_mapping[event_name] 410 return _on_attribute_to_event_name_mapping[event_name]
376 else: 411 else:
377 return event_name 412 return event_name
378 413
379 def _DomToHtmlEvents(interface_id, events): 414 def _DomToHtmlEvents(interface_id, events):
380 event_names = set(map(_OnAttributeToEventName, events)) 415 event_names = set(map(_OnAttributeToEventName, events))
381 if interface_id in _html_manual_events: 416 if interface_id in _html_manual_events:
382 for manual_event_name in _html_manual_events[interface_id]: 417 for manual_event_name in _html_manual_events[interface_id]:
383 event_names.add(manual_event_name) 418 event_names.add(manual_event_name)
384 419
385 return sorted(event_names, key=lambda name: _html_event_names[name]) 420 return sorted(event_names, key=lambda name: _html_event_names[name])
386 421
387 # ------------------------------------------------------------------------------ 422 # ------------------------------------------------------------------------------
423 class HtmlSystemShared(object):
388 424
389 class HtmlSystem(System): 425 def __init__(self, database, generator):
390
391 def __init__(self, templates, database, emitters, output_dir, generator):
392 super(HtmlSystem, self).__init__(
393 templates, database, emitters, output_dir)
394 self._event_classes = set() 426 self._event_classes = set()
395 self._seen_event_names = {} 427 self._seen_event_names = {}
428 self._database = database
396 self._generator = generator 429 self._generator = generator
397 430
398 def _AllowInHtmlLibrary(self, interface, member): 431 def _AllowInHtmlLibrary(self, interface, member, member_prefix):
399 if self._PrivateInHtmlLibrary(interface, member): 432 return not self._Matches(interface, member, member_prefix,
400 return False 433 _html_library_remove)
434
435 def _Matches(self, interface, member, member_prefix, candidates):
401 for interface_name in ([interface.id] + 436 for interface_name in ([interface.id] +
402 self._generator._AllImplementedInterfaces(interface)): 437 self._generator._AllImplementedInterfaces(interface)):
403 if interface.id + '.' + member in _html_library_remove: 438 if (DartType(interface_name) + '.' + member in candidates or
404 return False 439 DartType(interface_name) + '.' + member_prefix + member in candidates) :
sra1 2012/02/29 23:11:55 These two tests do the same when member_prefix='',
Jacob 2012/03/01 00:40:44 Clarified offline. The design is the table of matc
405 return True 440 return True
441 return False
406 442
407 def _PrivateInHtmlLibrary(self, interface, member): 443 def MaybeReturnDocument(self, return_type):
444 """
445 To make it appear that there are not a distinct Document and
446 HTMLHtmlElement (document.documentElement) objects we always use
447 documentElement instead of the regular document object so must not
448 allow a regular document to leak out.
449 """
450 # TODO(jacobr): any method that returns a Node could also theoretically
451 # really return a Document but there are alot of methods that return nodes
452 # and they all appear to be same. Consider the alternate strategy of
sra1 2012/02/29 23:11:55 same = sane?
Jacob 2012/03/01 00:40:44 same ==> safe :) done
453 # whitelisting just the known safe methods that return Nodes.
454 return (DartType(return_type) == 'EventTarget' or
455 DartType(return_type) == 'Document')
456
457 def RenameInHtmlLibrary(self, interface, member, member_prefix=''):
458 """
459 Returns the name of the member in the HTML library or None if the member is
460 suppressed in the HTML library
461 """
462 if not self._AllowInHtmlLibrary(interface, member, member_prefix):
463 return None
464
408 for interface_name in ([interface.id] + 465 for interface_name in ([interface.id] +
409 self._generator._AllImplementedInterfaces(interface)): 466 self._generator._AllImplementedInterfaces(interface)):
410 if (interface_name in _private_html_members and 467 name = interface.id + '.' + member
411 member in _private_html_members[interface_name]): 468 if name in _html_library_renames:
412 return True 469 return _html_library_renames[name]
413 return False 470 name = interface.id + '.' + member_prefix + member
471 if name in _html_library_renames:
472 return _html_library_renames[name]
473
474 if self._PrivateInHtmlLibrary(interface, member, member_prefix):
475 return '_' + member
476
477 # No rename required
478 return member
479
480 def _PrivateInHtmlLibrary(self, interface, member, member_prefix):
481 return self._Matches(interface, member, member_prefix,
482 _private_html_members)
414 483
415 # TODO(jacobr): this already exists 484 # TODO(jacobr): this already exists
416 def _TraverseParents(self, interface, callback): 485 def _TraverseParents(self, interface, callback):
417 for parent in interface.parents: 486 for parent in interface.parents:
418 parent_id = parent.type.id 487 parent_id = parent.type.id
419 if self._database.HasInterface(parent_id): 488 if self._database.HasInterface(parent_id):
420 parent_interface = self._database.GetInterface(parent_id) 489 parent_interface = self._database.GetInterface(parent_id)
421 callback(parent_interface) 490 callback(parent_interface)
422 self._TraverseParents(parent_interface, callback) 491 self._TraverseParents(parent_interface, callback)
423 492
424 # TODO(jacobr): this isn't quite right.... 493 # TODO(jacobr): this isn't quite right....
425 def _GetParentsEventsClasses(self, interface): 494 def GetParentsEventsClasses(self, interface):
426 # Ugly hack as we don't specify that Document inherits from Element 495 # Ugly hack as we don't specify that Document inherits from Element
427 # in our IDL. 496 # in our IDL.
428 if interface.id == 'Document': 497 if interface.id == 'Document':
429 return ['ElementEvents'] 498 return ['ElementEvents']
430 499
431 interfaces_with_events = set() 500 interfaces_with_events = set()
432 def visit(parent): 501 def visit(parent):
433 if parent.id in self._event_classes: 502 if parent.id in self._event_classes:
434 interfaces_with_events.add(parent) 503 interfaces_with_events.add(parent)
435 504
436 self._TraverseParents(interface, visit) 505 self._TraverseParents(interface, visit)
437 if len(interfaces_with_events) == 0: 506 if len(interfaces_with_events) == 0:
438 return ['Events'] 507 return ['Events']
439 else: 508 else:
440 names = [] 509 names = []
441 for interface in interfaces_with_events: 510 for interface in interfaces_with_events:
442 names.append(interface.id + 'Events') 511 names.append(interface.id + 'Events')
443 return names 512 return names
444 513
514 def _ImplClassName(self, type_name):
515 return '_' + type_name + 'Impl'
516
517 class HtmlSystem(System):
518
519 def __init__(self, templates, database, emitters, output_dir, generator):
520 super(HtmlSystem, self).__init__(
521 templates, database, emitters, output_dir)
522 self._shared = HtmlSystemShared(database, generator)
523
445 class HtmlInterfacesSystem(HtmlSystem): 524 class HtmlInterfacesSystem(HtmlSystem):
446 525
447 def __init__(self, templates, database, emitters, output_dir, generator): 526 def __init__(self, templates, database, emitters, output_dir, generator):
448 super(HtmlInterfacesSystem, self).__init__( 527 super(HtmlInterfacesSystem, self).__init__(
449 templates, database, emitters, output_dir, generator) 528 templates, database, emitters, output_dir, generator)
450 self._dart_interface_file_paths = [] 529 self._dart_interface_file_paths = []
451 530
452 def InterfaceGenerator(self, 531 def InterfaceGenerator(self,
453 interface, 532 interface,
454 common_prefix, 533 common_prefix,
455 super_interface_name, 534 super_interface_name,
456 source_filter): 535 source_filter):
457 """.""" 536 """."""
458 interface_name = interface.id 537 interface_name = interface.id
459 dart_interface_file_path = self._FilePathForDartInterface(interface_name) 538 dart_interface_file_path = self._FilePathForDartInterface(interface_name)
460 539
461 self._dart_interface_file_paths.append(dart_interface_file_path) 540 self._dart_interface_file_paths.append(dart_interface_file_path)
462 541
463 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) 542 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path)
464 543
465 template_file = 'interface_%s.darttemplate' % interface_name 544 template_file = 'interface_%s.darttemplate' % interface_name
466 template = self._templates.TryLoad(template_file) 545 template = self._templates.TryLoad(template_file)
467 if not template: 546 if not template:
468 template = self._templates.Load('interface.darttemplate') 547 template = self._templates.Load('interface.darttemplate')
469 548
470 return HtmlDartInterfaceGenerator( 549 return HtmlDartInterfaceGenerator(
471 interface, dart_interface_code, 550 interface, dart_interface_code,
472 template, 551 template,
473 common_prefix, super_interface_name, 552 common_prefix, super_interface_name,
474 source_filter, self) 553 source_filter, self, self._shared)
475 554
476 def ProcessCallback(self, interface, info): 555 def ProcessCallback(self, interface, info):
477 """Generates a typedef for the callback interface.""" 556 """Generates a typedef for the callback interface."""
478 interface_name = interface.id 557 interface_name = interface.id
479 file_path = self._FilePathForDartInterface(interface_name) 558 file_path = self._FilePathForDartInterface(interface_name)
480 self._ProcessCallback(interface, info, file_path) 559 self._ProcessCallback(interface, info, file_path)
481 560
482 def GenerateLibraries(self, lib_dir): 561 def GenerateLibraries(self, lib_dir):
483 pass 562 pass
484 563
485 564
486 def _FilePathForDartInterface(self, interface_name): 565 def _FilePathForDartInterface(self, interface_name):
487 """Returns the file path of the Dart interface definition.""" 566 """Returns the file path of the Dart interface definition."""
488 # TODO(jmesserly): is this the right path 567 # TODO(jmesserly): is this the right path
489 return os.path.join(self._output_dir, 'html', 'interface', 568 return os.path.join(self._output_dir, 'html', 'interface',
490 '%s.dart' % interface_name) 569 '%s.dart' % interface_name)
491 570
492 # ------------------------------------------------------------------------------ 571 # ------------------------------------------------------------------------------
493 572
494 # TODO(jmesserly): inheritance is probably not the right way to factor this long 573 # TODO(jmesserly): inheritance is probably not the right way to factor this long
495 # term, but it makes merging better for now. 574 # term, but it makes merging better for now.
496 class HtmlDartInterfaceGenerator(DartInterfaceGenerator): 575 class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
497 """Generates Dart Interface definition for one DOM IDL interface.""" 576 """Generates Dart Interface definition for one DOM IDL interface."""
498 577
499 def __init__(self, interface, emitter, template, 578 def __init__(self, interface, emitter, template,
500 common_prefix, super_interface, source_filter, system): 579 common_prefix, super_interface, source_filter, system, shared):
501 super(HtmlDartInterfaceGenerator, self).__init__(interface, 580 super(HtmlDartInterfaceGenerator, self).__init__(interface,
502 emitter, template, common_prefix, super_interface, source_filter) 581 emitter, template, common_prefix, super_interface, source_filter)
503 self._system = system 582 self._system = system
583 self._shared = shared
504 584
505 def StartInterface(self): 585 def StartInterface(self):
506 typename = self._interface.id 586 typename = self._interface.id
507 587
508 extends = [] 588 extends = []
509 suppressed_extends = [] 589 suppressed_extends = []
510 590
511 for parent in self._interface.parents: 591 for parent in self._interface.parents:
512 # TODO(vsm): Remove source_filter. 592 # TODO(vsm): Remove source_filter.
513 if MatchSourceFilter(self._source_filter, parent): 593 if MatchSourceFilter(self._source_filter, parent):
514 # Parent is a DOM type. 594 # Parent is a DOM type.
515 extends.append(DartType(parent.type.id)) 595 extends.append(DartType(parent.type.id))
516 elif '<' in parent.type.id: 596 elif '<' in parent.type.id:
517 # Parent is a Dart collection type. 597 # Parent is a Dart collection type.
518 # TODO(vsm): Make this check more robust. 598 # TODO(vsm): Make this check more robust.
519 extends.append(parent.type.id) 599 extends.append(DartType(parent.type.id))
520 else: 600 else:
521 suppressed_extends.append('%s.%s' % 601 suppressed_extends.append('%s.%s' %
522 (self._common_prefix, parent.type.id)) 602 (self._common_prefix, DartType(parent.type.id)))
523 603
524 comment = ' extends' 604 comment = ' extends'
525 extends_str = '' 605 extends_str = ''
526 if extends: 606 if extends:
527 extends_str += ' extends ' + ', '.join(extends) 607 extends_str += ' extends ' + ', '.join(extends)
528 comment = ',' 608 comment = ','
529 if suppressed_extends: 609 if suppressed_extends:
530 extends_str += ' /*%s %s */' % (comment, ', '.join(suppressed_extends)) 610 extends_str += ' /*%s %s */' % (comment, ', '.join(suppressed_extends))
531 611
532 if typename in interface_factories: 612 if typename in interface_factories:
(...skipping 12 matching lines...) Expand all
545 '\n' 625 '\n'
546 ' $CTOR(int length);\n' 626 ' $CTOR(int length);\n'
547 '\n' 627 '\n'
548 ' $CTOR.fromList(List<$TYPE> list);\n' 628 ' $CTOR.fromList(List<$TYPE> list);\n'
549 '\n' 629 '\n'
550 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n', 630 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n',
551 CTOR=self._interface.id, 631 CTOR=self._interface.id,
552 TYPE=DartType(element_type)) 632 TYPE=DartType(element_type))
553 633
554 def AddAttribute(self, getter, setter): 634 def AddAttribute(self, getter, setter):
555 if getter and not self._system._AllowInHtmlLibrary(self._interface, 635 html_getter_name = self._shared.RenameInHtmlLibrary(
556 'get:' + getter.id): 636 self._interface, getter.id, 'get:')
637 html_setter_name = self._shared.RenameInHtmlLibrary(
638 self._interface, getter.id, 'set:')
639
640 if not html_getter_name:
557 getter = None 641 getter = None
558 if setter and not self._system._AllowInHtmlLibrary(self._interface, 642 if not html_setter_name:
559 'set:' + setter.id):
560 setter = None 643 setter = None
561 if not getter and not setter: 644 if not getter and not setter:
562 return 645 return
563 if getter and setter and DartType(getter.type.id) == DartType(setter.type.id ): 646
647 # We don't yet handle inconsistent renames of the getter and setter yet.
648 if html_getter_name and html_setter_name:
649 assert html_getter_name == html_setter_name
650 if (getter and setter and
651 DartType(getter.type.id) == DartType(setter.type.id)):
564 self._members_emitter.Emit('\n $TYPE $NAME;\n', 652 self._members_emitter.Emit('\n $TYPE $NAME;\n',
565 NAME=getter.id, TYPE=DartType(getter.type.id)); 653 NAME=html_getter_name,
654 TYPE=DartType(getter.type.id));
566 return 655 return
567 if getter and not setter: 656 if getter and not setter:
568 self._members_emitter.Emit('\n final $TYPE $NAME;\n', 657 self._members_emitter.Emit('\n final $TYPE $NAME;\n',
569 NAME=getter.id, TYPE=DartType(getter.type.id)); 658 NAME=html_getter_name,
659 TYPE=DartType(getter.type.id));
570 return 660 return
571 raise Exception('Unexpected getter/setter combination %s %s' % 661 raise Exception('Unexpected getter/setter combination %s %s' %
572 (getter, setter)) 662 (getter, setter))
573 663
574 def AddOperation(self, info): 664 def AddOperation(self, info):
575 """ 665 """
576 Arguments: 666 Arguments:
577 operations - contains the overloads, one or more operations with the same 667 operations - contains the overloads, one or more operations with the same
578 name. 668 name.
579 """ 669 """
580 if self._system._AllowInHtmlLibrary(self._interface, info.name): 670 html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
671 if html_name:
581 self._members_emitter.Emit('\n' 672 self._members_emitter.Emit('\n'
582 ' $TYPE $NAME($PARAMS);\n', 673 ' $TYPE $NAME($PARAMS);\n',
583 TYPE=info.type_name, 674 TYPE=info.type_name,
584 NAME=info.name, 675 NAME=html_name,
585 PARAMS=info.ParametersInterfaceDeclaration()) 676 PARAMS=info.ParametersInterfaceDeclaration())
586 677
587 def FinishInterface(self): 678 def FinishInterface(self):
588 pass 679 pass
589 680
590 def AddConstant(self, constant): 681 def AddConstant(self, constant):
591 self._EmitConstant(self._members_emitter, constant) 682 self._EmitConstant(self._members_emitter, constant)
592 683
593 def AddEventAttributes(self, event_attrs): 684 def AddEventAttributes(self, event_attrs):
594 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs) 685 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
595 self._system._event_classes.add(self._interface.id) 686 self._shared._event_classes.add(self._interface.id)
596 events_interface = self._interface.id + 'Events' 687 events_interface = self._interface.id + 'Events'
597 self._members_emitter.Emit('\n $TYPE get on();\n', 688 self._members_emitter.Emit('\n $TYPE get on();\n',
598 TYPE=events_interface) 689 TYPE=events_interface)
599 events_members = self._emitter.Emit( 690 events_members = self._emitter.Emit(
600 '\ninterface $INTERFACE extends $PARENTS {\n$!MEMBERS}\n', 691 '\ninterface $INTERFACE extends $PARENTS {\n$!MEMBERS}\n',
601 INTERFACE=events_interface, 692 INTERFACE=events_interface,
602 PARENTS=', '.join( 693 PARENTS=', '.join(
603 self._system._GetParentsEventsClasses(self._interface))) 694 self._shared.GetParentsEventsClasses(self._interface)))
604 695
605 for event_name in event_attrs: 696 for event_name in event_attrs:
606 if event_name in _html_event_names: 697 if event_name in _html_event_names:
607 events_members.Emit('\n EventListenerList get $NAME();\n', 698 events_members.Emit('\n EventListenerList get $NAME();\n',
608 NAME=_html_event_names[event_name]) 699 NAME=_html_event_names[event_name])
609 else: 700 else:
610 raise Exception('No known html even name for event: ' + event_name) 701 raise Exception('No known html even name for event: ' + event_name)
611 702
612 # ------------------------------------------------------------------------------ 703 # ------------------------------------------------------------------------------
613 704
614 # TODO(jmesserly): inheritance is probably not the right way to factor this long 705 # TODO(jmesserly): inheritance is probably not the right way to factor this long
615 # term, but it makes merging better for now. 706 # term, but it makes merging better for now.
616 class HtmlFrogClassGenerator(FrogInterfaceGenerator): 707 class HtmlFrogClassGenerator(FrogInterfaceGenerator):
617 """Generates a Frog class for the dart:html library from a DOM IDL 708 """Generates a Frog class for the dart:html library from a DOM IDL
618 interface. 709 interface.
619 """ 710 """
620 711
621 def __init__(self, system, interface, template, super_interface, dart_code): 712 def __init__(self, system, interface, template, super_interface, dart_code,
713 shared):
622 super(HtmlFrogClassGenerator, self).__init__( 714 super(HtmlFrogClassGenerator, self).__init__(
623 system, interface, template, super_interface, dart_code) 715 system, interface, template, super_interface, dart_code)
716 self._shared = shared
624 717
718 def _ImplClassName(self, type_name):
719 return self._shared._ImplClassName(type_name)
625 720
626 def StartInterface(self): 721 def StartInterface(self):
627 interface = self._interface 722 interface = self._interface
628 interface_name = interface.id 723 interface_name = interface.id
629 724
630 self._class_name = self._ImplClassName(interface_name) 725 self._class_name = self._ImplClassName(interface_name)
631 726
632 base = None 727 base = None
633 if interface.parents: 728 if interface.parents:
634 supertype = interface.parents[0].type.id 729 supertype = interface.parents[0].type.id
635 # FIXME: We're currently injecting List<..> and EventTarget as
636 # supertypes in dart.idl. We should annotate/preserve as
637 # attributes instead. For now, this hack lets the interfaces
638 # inherit, but not the classes.
639 if (not IsDartListType(supertype) and
640 not supertype == 'EventTarget'):
641 base = self._ImplClassName(supertype)
642 if IsDartCollectionType(supertype): 730 if IsDartCollectionType(supertype):
643 # List methods are injected in AddIndexer. 731 # List methods are injected in AddIndexer.
644 pass 732 pass
645 elif supertype == 'EventTarget':
646 # Most implementors of EventTarget specify the EventListener operations
647 # again. If the operations are not specified, try to inherit from the
648 # EventTarget implementation.
649 #
650 # Applies to MessagePort.
651 if not [op for op in interface.operations if op.id == 'addEventListener' ]:
652 base = self._ImplClassName(supertype)
653 else: 733 else:
654 base = self._ImplClassName(supertype) 734 base = self._ImplClassName(supertype)
655 735
656 native_spec = MakeNativeSpec(interface.javascript_binding_name) 736 native_spec = MakeNativeSpec(interface.javascript_binding_name)
657 737
658 extends = ' extends ' + base if base else '' 738 extends = ' extends ' + base if base else ''
659 739
660 # TODO: Include all implemented interfaces, including other Lists. 740 # TODO: Include all implemented interfaces, including other Lists.
661 implements = [interface_name] 741 implements = [interface_name]
662 element_type = MaybeTypedArrayElementType(self._interface) 742 element_type = MaybeTypedArrayElementType(self._interface)
663 if element_type: 743 if element_type:
664 implements.append('List<%s>' % DartType(element_type)) 744 implements.append('List<%s>' % DartType(element_type))
665 745
666 self._members_emitter = self._dart_code.Emit( 746 self._members_emitter = self._dart_code.Emit(
667 self._template, 747 self._template,
668 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { 748 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
669 #$!MEMBERS 749 #$!MEMBERS
670 #} 750 #}
671 CLASSNAME=self._class_name, 751 CLASSNAME=self._class_name,
672 EXTENDS=extends, 752 EXTENDS=extends,
673 IMPLEMENTS=' implements ' + ', '.join(implements), 753 IMPLEMENTS=' implements ' + ', '.join(implements),
674 NATIVESPEC=' native "' + native_spec + '"') 754 NATIVESPEC=' native "' + native_spec + '"')
675 755
676 element_type = MaybeTypedArrayElementType(interface)
677 if element_type: 756 if element_type:
678 self.AddTypedArrayConstructors(element_type) 757 self.AddTypedArrayConstructors(element_type)
679 758
759 def AddIndexer(self, element_type):
760 """Adds all the methods required to complete implementation of List."""
761 # We would like to simply inherit the implementation of everything except
762 # get length(), [], and maybe []=. It is possible to extend from a base
763 # array implementation class only when there is no other implementation
764 # inheritance. There might be no implementation inheritance other than
765 # DOMBaseWrapper for many classes, but there might be some where the
766 # array-ness is introduced by a non-root interface:
767 #
768 # interface Y extends X, List<T> ...
769 #
770 # In the non-root case we have to choose between:
771 #
772 # class YImpl extends XImpl { add List<T> methods; }
773 #
774 # and
775 #
776 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
777 #
778 self._members_emitter.Emit(
779 '\n'
780 ' $TYPE operator[](int index) native "return this[index];";\n',
781 TYPE=self._NarrowOutputType(element_type))
782
783 if 'CustomIndexedSetter' in self._interface.ext_attrs:
784 self._members_emitter.Emit(
785 '\n'
786 ' void operator[]=(int index, $TYPE value) native "this[index] = valu e";\n',
787 TYPE=self._NarrowInputType(element_type))
788 else:
789 # The HTML library implementation of NodeList has a custom indexed setter
790 # implementation that uses the parent node the NodeList is associated
791 # with if one is available.
792 if self._interface.id != 'NodeList':
793 self._members_emitter.Emit(
794 '\n'
795 ' void operator[]=(int index, $TYPE value) {\n'
796 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
797 ' }\n',
798 TYPE=self._NarrowInputType(element_type))
799
800 # TODO(sra): Use separate mixins for mutable implementations of List<T>.
801 # TODO(sra): Use separate mixins for typed array implementations of List<T>.
802 if self._interface.id != 'NodeList':
803 template_file = 'immutable_list_mixin.darttemplate'
804 template = self._system._templates.Load(template_file)
805 self._members_emitter.Emit(template, E=DartType(element_type))
806
680 def AddAttribute(self, getter, setter): 807 def AddAttribute(self, getter, setter):
681 808
682 if self._system._PrivateInHtmlLibrary(self._interface, getter.id): 809 html_getter_name = self._shared.RenameInHtmlLibrary(
683 if getter: 810 self._interface, getter.id, 'get:')
684 self._AddGetter(getter, True) 811 html_setter_name = self._shared.RenameInHtmlLibrary(
685 if setter: 812 self._interface, getter.id, 'set:')
686 self._AddSetter(setter, True) 813
687 return 814 if not html_getter_name:
688 if getter and not self._system._AllowInHtmlLibrary(self._interface,
689 'get:' + getter.id):
690 getter = None 815 getter = None
691 if setter and not self._system._AllowInHtmlLibrary(self._interface, 816 if not html_setter_name:
692 'set:' + setter.id):
693 setter = None 817 setter = None
818
694 if not getter and not setter: 819 if not getter and not setter:
695 return 820 return
821
822 if ((getter and (html_getter_name != getter.id or
823 self._shared.MaybeReturnDocument(getter.type.id))) or
824 (setter and (html_setter_name != setter.id or
825 self._shared.MaybeReturnDocument(setter.type.id))) or
826 self._interface.id == 'Document'):
827 if getter:
828 self._AddRenamingGetter(getter, html_getter_name)
829 if setter:
830 self._AddRenamingSetter(setter, html_setter_name)
831 return
832
696 # If the (getter, setter) pair is shadowing, we can't generate a shadowing 833 # If the (getter, setter) pair is shadowing, we can't generate a shadowing
697 # field (Issue 1633). 834 # field (Issue 1633).
698 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) 835 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter)
699 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) 836 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter)
700 if super_getter or super_setter: 837 if super_getter or super_setter:
701 if getter and not setter and super_getter and not super_setter: 838 if getter and not setter and super_getter and not super_setter:
702 if getter.type.id == super_getter.type.id: 839 if DartType(getter.type.id) == DartType(super_getter.type.id):
703 # Compatible getter, use the superclass property. This works because 840 # Compatible getter, use the superclass property. This works because
704 # JavaScript will do its own dynamic dispatch. 841 # JavaScript will do its own dynamic dispatch.
705 output_type = getter and self._NarrowOutputType(getter.type.id) 842 output_type = getter and self._NarrowOutputType(getter.type.id)
706 self._members_emitter.Emit( 843 self._members_emitter.Emit(
707 '\n' 844 '\n'
708 ' // Use implementation from $SUPER.\n' 845 ' // Use implementation from $SUPER.\n'
709 ' // final $TYPE $NAME;\n', 846 ' // final $TYPE $NAME;\n',
710 SUPER=super_getter_interface.id, 847 SUPER=super_getter_interface.id,
711 NAME=getter.id, TYPE=output_type) 848 NAME=getter.id, TYPE=output_type)
712 return 849 return
713 850
714 self._members_emitter.Emit('\n // Shadowing definition.') 851 self._members_emitter.Emit('\n // Shadowing definition.')
715 if getter: 852 if getter:
sra1 2012/02/29 23:11:55 _AddAttributeUsingProperties? Otherwise you might
Jacob 2012/03/01 00:40:44 Done.
716 self._AddGetter(getter, False) 853 self._AddGetter(getter)
717 if setter: 854 if setter:
718 self._AddSetter(setter, False) 855 self._AddSetter(setter)
719 return 856 return
720 857
721 if self._interface.id != 'Document': 858 output_type = getter and self._NarrowOutputType(getter.type.id)
722 output_type = getter and self._NarrowOutputType(getter.type.id) 859 input_type = setter and self._NarrowInputType(setter.type.id)
723 input_type = setter and self._NarrowInputType(setter.type.id) 860 if getter and setter and input_type == output_type:
724 if getter and setter and input_type == output_type: 861 self._members_emitter.Emit(
725 self._members_emitter.Emit( 862 '\n $TYPE $NAME;\n',
726 '\n $TYPE $NAME;\n', 863 NAME=getter.id, TYPE=output_type)
727 NAME=getter.id, TYPE=output_type) 864 return
728 return 865 if getter and not setter:
729 if getter and not setter: 866 self._members_emitter.Emit(
730 self._members_emitter.Emit( 867 '\n final $TYPE $NAME;\n',
731 '\n final $TYPE $NAME;\n', 868 NAME=getter.id, TYPE=output_type)
732 NAME=getter.id, TYPE=output_type) 869 return
733 return 870 self._AddAttributeUsingProperties(getter, setter)
734 self._AddAttributeUsingProperties(getter, setter, False)
735 871
736 def _AddAttributeUsingProperties(self, getter, setter, private): 872 def _AddAttributeUsingProperties(self, getter, setter):
737 if getter: 873 if getter:
738 self._AddGetter(getter, private) 874 self._AddGetter(getter)
739 if setter: 875 if setter:
740 self._AddSetter(setter, private) 876 self._AddSetter(setter)
741 877
742 def _AddGetter(self, attr, private): 878 def _AddGetter(self, attr):
743 # TODO(sra): Remove native body when Issue 829 fixed. 879 self._AddRenamingGetter(attr, attr.id)
880
881 def _AddSetter(self, attr):
882 self._AddRenamingSetter(attr, attr.id)
883
884 def _AddRenamingGetter(self, attr, html_name):
885 return_type = self._NarrowOutputType(attr.type.id)
886 if self._shared.MaybeReturnDocument(attr.type.id):
887 self._members_emitter.Emit(
888 '\n $TYPE get $(HTML_NAME)() => '
889 '_FixHtmlDocumentReference(_$(HTML_NAME));\n',
890 HTML_NAME=html_name,
891 NAME=attr.id, TYPE=return_type,
sra1 2012/02/29 23:11:55 I think it is easier to find TYPE if it is on its
Jacob 2012/03/01 00:40:44 Done.
892 THIS='this.parentNode' if self._interface.id == 'Document' else 'this'
sra1 2012/02/29 23:11:55 THIS is not used
Jacob 2012/03/01 00:40:44 Done.
893 )
894 html_name = '_' + html_name
895 # For correctness this needs to be the return type of the native helper
896 # method due to the fact that the real HTMLDocument object is not typed
897 # as a document. TODO(jacobr): we could simplify this.
898 return_type = '_EventTargetImpl'
899
744 self._members_emitter.Emit( 900 self._members_emitter.Emit(
745 '\n $TYPE get $PRIVATE$NAME() native "return $THIS.$NAME;";\n', 901 '\n $TYPE get $(HTML_NAME)() native "return $(THIS).$NAME;";\n',
746 NAME=attr.id, TYPE=self._NarrowOutputType(attr.type.id), 902 HTML_NAME=html_name,
747 PRIVATE='_' if private else '', 903 NAME=attr.id, TYPE=return_type,
748 THIS='this.parentNode' if self._interface.id == 'Document' else 'this' 904 THIS='this.parentNode' if self._interface.id == 'Document' else 'this'
749 ) 905 )
750 906
751 def _AddSetter(self, attr, private): 907 def _AddRenamingSetter(self, attr, html_name):
752 # TODO(sra): Remove native body when Issue 829 fixed.
753 self._members_emitter.Emit( 908 self._members_emitter.Emit(
754 '\n void set $PRIVATE$NAME($TYPE value)' 909 '\n void set $HTML_NAME($TYPE value)'
755 ' native "$THIS.$NAME = value;";\n', 910 ' native "$(THIS).$NAME = value;";\n',
911 HTML_NAME=html_name,
756 NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id), 912 NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id),
757 PRIVATE='_' if private else '',
758 THIS='this.parentNode' if self._interface.id == 'Document' else 'this') 913 THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
759 914
760 def AddOperation(self, info): 915 def AddOperation(self, info):
761 """ 916 """
762 Arguments: 917 Arguments:
763 info: An OperationInfo object. 918 info: An OperationInfo object.
764 """ 919 """
765 private_in_html = self._system._PrivateInHtmlLibrary(self._interface, 920 html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
766 info.name) 921 if not html_name:
767 if private_in_html or self._interface.id == 'Document': 922 return
768 # TODO(vsm): Handle overloads. 923
769 # TODO(jacobr): handle document more efficiently for cases where any 924 maybe_return_document = self._shared.MaybeReturnDocument(info.type_name)
770 # document is fine. For example: use window.document instead of 925
771 # this.parentNode. 926 if (self._interface.id == 'Document' or html_name != info.name or
sra1 2012/02/29 23:11:55 Why self._interface.id == 'Document' ok I see - 't
Jacob 2012/03/01 00:40:44 Good comments. Done. On 2012/02/29 23:11:55, sra1
927 info.type_name == 'Document') or maybe_return_document:
sra1 2012/02/29 23:11:55 Is info.typename == 'Doc' redundant with maybe_ret
Jacob 2012/03/01 00:40:44 fixed. That was legacy.
928
929 # For example: use window.document instead of his.parentNode.
772 return_type = self._NarrowOutputType(info.type_name) 930 return_type = self._NarrowOutputType(info.type_name)
931 if maybe_return_document:
932 assert len(info.overloads) == 1
933 self._members_emitter.Emit(
934 '\n'
935 ' $TYPE $(HTML_NAME)($PARAMS) => '
936 '_FixHtmlDocumentReference(_$(HTML_NAME)($PARAMNAMES));\n',
937 TYPE=return_type,
938 HTML_NAME=html_name,
939 PARAMNAMES=info.ParametersAsArgumentList(),
940 PARAMS=info.ParametersImplementationDeclaration(
941 lambda type_name: self._NarrowInputType(type_name)))
942 html_name = '_' + html_name
943 # For correctness this needs to be the return type of the native helper
944 # method due to the fact that the real HTMLDocument object is not typed
945 # as a document. TODO(jacobr): we could simplify this.
946 return_type = '_EventTargetImpl'
sra1 2012/02/29 23:11:55 This muck-with-the-names-and-fall-through logic is
Jacob 2012/03/01 00:40:44 Nice. That makes the code better.
947
948
773 self._members_emitter.Emit( 949 self._members_emitter.Emit(
774 '\n' 950 '\n'
775 ' $TYPE $PRIVATE$NAME($PARAMS)' 951 ' $TYPE $(HTML_NAME)($PARAMS)'
776 ' native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n', 952 ' native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n',
777 TYPE=return_type, 953 TYPE=return_type,
778 RETURN='' if return_type == 'void' else 'return ', 954 RETURN='' if return_type == 'void' else 'return ',
955 HTML_NAME=html_name,
779 NAME=info.name, 956 NAME=info.name,
780 PRIVATE='_' if private_in_html else '',
781 THIS='this.parentNode' if self._interface.id == 'Document' 957 THIS='this.parentNode' if self._interface.id == 'Document'
782 else 'this', 958 else 'this',
783 PARAMNAMES=info.ParametersAsArgumentList(), 959 PARAMNAMES=info.ParametersAsArgumentList(),
784 PARAMS=info.ParametersImplementationDeclaration( 960 PARAMS=info.ParametersImplementationDeclaration(
785 lambda type_name: self._NarrowInputType(type_name))) 961 lambda type_name: self._NarrowInputType(type_name)))
786 elif self._system._AllowInHtmlLibrary(self._interface, info.name): 962 else:
787 # TODO(jacobr): this is duplicated from the parent class.
788 self._members_emitter.Emit( 963 self._members_emitter.Emit(
789 '\n' 964 '\n'
790 ' $TYPE $NAME($PARAMS) native;\n', 965 ' $TYPE $NAME($PARAMS) native;\n',
791 TYPE=self._NarrowOutputType(info.type_name), 966 TYPE=self._NarrowOutputType(info.type_name),
792 NAME=info.name, 967 NAME=info.name,
793 PARAMS=info.ParametersImplementationDeclaration( 968 PARAMS=info.ParametersImplementationDeclaration(
794 lambda type_name: self._NarrowInputType(type_name))) 969 lambda type_name: self._NarrowInputType(type_name)))
795 970
796 def AddEventAttributes(self, event_attrs): 971 def AddEventAttributes(self, event_attrs):
797 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs) 972 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
798 events_class = '_' + self._interface.id + 'EventsImpl' 973 events_class = '_' + self._interface.id + 'EventsImpl'
799 events_interface = self._interface.id + 'Events' 974 events_interface = self._interface.id + 'Events'
800 self._members_emitter.Emit( 975 self._members_emitter.Emit(
801 '\n $TYPE get on() =>\n new $TYPE($EVENTTARGET);\n', 976 '\n $TYPE get on() =>\n new $TYPE($EVENTTARGET);\n',
802 TYPE=events_class, 977 TYPE=events_class,
803 EVENTTARGET='_jsDocument' if self._interface.id == 'Document' 978 EVENTTARGET='_jsDocument' if self._interface.id == 'Document'
804 else 'this') 979 else 'this')
805 980
806 self._system._event_classes.add(self._interface.id) 981 self._shared._event_classes.add(self._interface.id)
807 982
808 parent_event_classes = self._system._GetParentsEventsClasses( 983 parent_event_classes = self._shared.GetParentsEventsClasses(
809 self._interface) 984 self._interface)
810 if len(parent_event_classes) != 1: 985 if len(parent_event_classes) != 1:
811 raise Exception('Only one parent event class allowed ' 986 raise Exception('Only one parent event class allowed '
812 + self._interface.id) 987 + self._interface.id)
813 988
814 # TODO(jacobr): specify the type of _ptr as EventTarget 989 # TODO(jacobr): specify the type of _ptr as EventTarget
815 events_members = self._dart_code.Emit( 990 events_members = self._dart_code.Emit(
816 '\n' 991 '\n'
817 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n' 992 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
818 ' $CLASSNAME(_ptr) : super(_ptr);\n' 993 ' $CLASSNAME(_ptr) : super(_ptr);\n'
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) 1026 dart_frog_file_path = self._FilePathForFrogImpl(interface.id)
852 self._dart_frog_file_paths.append(dart_frog_file_path) 1027 self._dart_frog_file_paths.append(dart_frog_file_path)
853 1028
854 template_file = 'impl_%s.darttemplate' % interface.id 1029 template_file = 'impl_%s.darttemplate' % interface.id
855 template = self._templates.TryLoad(template_file) 1030 template = self._templates.TryLoad(template_file)
856 if not template: 1031 if not template:
857 template = self._templates.Load('frog_impl.darttemplate') 1032 template = self._templates.Load('frog_impl.darttemplate')
858 1033
859 dart_code = self._emitters.FileEmitter(dart_frog_file_path) 1034 dart_code = self._emitters.FileEmitter(dart_frog_file_path)
860 return HtmlFrogClassGenerator(self, interface, template, 1035 return HtmlFrogClassGenerator(self, interface, template,
861 super_interface_name, dart_code) 1036 super_interface_name, dart_code, self._shared)
862 1037
863 def GenerateLibraries(self, lib_dir): 1038 def GenerateLibraries(self, lib_dir):
864 self._GenerateLibFile( 1039 self._GenerateLibFile(
865 'html_frog.darttemplate', 1040 'html_frog.darttemplate',
866 os.path.join(lib_dir, 'html_frog.dart'), 1041 os.path.join(lib_dir, 'html_frog.dart'),
867 (self._interface_system._dart_interface_file_paths + 1042 (self._interface_system._dart_interface_file_paths +
868 self._interface_system._dart_callback_file_paths + 1043 self._interface_system._dart_callback_file_paths +
869 self._dart_frog_file_paths)) 1044 self._dart_frog_file_paths))
870 1045
871 def Finish(self): 1046 def Finish(self):
872 pass 1047 pass
873 1048
874 def _FilePathForFrogImpl(self, interface_name): 1049 def _FilePathForFrogImpl(self, interface_name):
875 """Returns the file path of the Frog implementation.""" 1050 """Returns the file path of the Frog implementation."""
876 # TODO(jmesserly): is this the right path 1051 # TODO(jmesserly): is this the right path
877 return os.path.join(self._output_dir, 'html', 'frog', 1052 return os.path.join(self._output_dir, 'html', 'frog',
878 '%s.dart' % interface_name) 1053 '%s.dart' % interface_name)
879 1054
1055 # -----------------------------------------------------------------------------
1056
1057 class HtmlDartiumSystem(HtmlSystem):
1058
1059 def __init__(self, templates, database, emitters, output_dir, generator):
1060 """Prepared for generating wrapping implementation.
1061
1062 - Creates emitter for Dart code.
1063 """
1064 super(HtmlDartiumSystem, self).__init__(
1065 templates, database, emitters, output_dir, generator)
1066 self._shared = HtmlSystemShared(database, generator)
1067 self._dart_dartium_file_paths = []
1068 self._wrap_cases = []
1069
1070 def InterfaceGenerator(self,
1071 interface,
1072 common_prefix,
1073 super_interface_name,
1074 source_filter):
1075 """."""
1076 dart_dartium_file_path = self._FilePathForImpl(interface.id)
1077 self._dart_dartium_file_paths.append(dart_dartium_file_path)
1078
1079 template_file = 'impl_%s.darttemplate' % interface.id
1080 template = self._templates.TryLoad(template_file)
1081 # TODO(jacobr): change this name as it is confusing.
1082 if not template:
1083 template = self._templates.Load('frog_impl.darttemplate')
1084
1085 dart_code = self._emitters.FileEmitter(dart_dartium_file_path)
1086 return HtmlDartiumInterfaceGenerator(self, interface, template,
1087 super_interface_name, dart_code, self._BaseDefines(interface),
1088 self._shared)
1089
1090 def _FilePathForImpl(self, interface_name):
1091 """Returns the file path of the Frog implementation."""
1092 # TODO(jmesserly): is this the right path
1093 return os.path.join(self._output_dir, 'html', 'dartium',
1094 '%s.dart' % interface_name)
1095
1096 def ProcessCallback(self, interface, info):
1097 pass
1098
1099 def GenerateLibraries(self, lib_dir):
1100 # Library generated for implementation.
1101 self._GenerateLibFile(
1102 'html_dartium.darttemplate',
1103 os.path.join(lib_dir, 'html_dartium.dart'),
1104 (self._interface_system._dart_interface_file_paths +
1105 self._interface_system._dart_callback_file_paths +
1106 # FIXME: Move the implementation to a separate library.
1107 self._dart_dartium_file_paths
1108 ),
1109 WRAPCASES='\n'.join(self._wrap_cases))
1110
1111 def Finish(self):
1112 pass
1113
1114 def _FilePathForDartWrappingImpl(self, interface_name):
sra1 2012/02/29 23:11:55 Unused?
Jacob 2012/03/01 00:40:44 Done.
1115 """Returns the file path of the html dartium wrapping implementation."""
1116 return os.path.join(self._output_dir, 'html', 'wrapping',
1117 '_%s.dart' % interface_name)
1118
880 # ------------------------------------------------------------------------------ 1119 # ------------------------------------------------------------------------------
881 1120
882 class WrappingInterfaceGenerator(object): 1121 # TODO(jacobr): there is far too much duplicated code between these bindings
883 """Generates Dart and JS implementation for one DOM IDL interface.""" 1122 # and the Frog bindings. A larger scale refactoring needs to be performed to
1123 # reduce the duplicated logic.
1124 class HtmlDartiumInterfaceGenerator(object):
1125 """Generates a wrapper based implementation fo the HTML library that works
1126 on Dartium. This is not intended to be the final solution for implementing
1127 dart:html on Dartium. Eventually we should generate direct wrapperless
1128 dart:html bindings that work on dartium."""
884 1129
885 def __init__(self, interface, super_interface, dart_code, base_members): 1130 def __init__(self, system, interface, template, super_interface, dart_code,
886 """Generates Dart and JS code for the given interface. 1131 base_members, shared):
1132 """Generates Dart wrapper code for the given interface.
887 1133
888 Args: 1134 Args:
889 1135
890 interface: an IDLInterface instance. It is assumed that all types have 1136 interface: an IDLInterface instance. It is assumed that all types have
891 been converted to Dart types (e.g. int, String), unless they are in 1137 been converted to Dart types (e.g. int, String), unless they are in
892 the same package as the interface. 1138 the same package as the interface.
893 super_interface: A string or None, the name of the common interface that 1139 super_interface: A string or None, the name of the common interface that
894 this interface implements, if any. 1140 this interface implements, if any.
895 dart_code: an Emitter for the file containing the Dart implementation 1141 dart_code: an Emitter for the file containing the Dart implementation
896 class. 1142 class.
897 base_members: a set of names of members defined in a base class. This is 1143 base_members: a set of names of members defined in a base class. This is
898 used to avoid static member 'overriding' in the generated Dart code. 1144 used to avoid static member 'overriding' in the generated Dart code.
1145 shared: functionaly shared across all Html generators.
sra1 2012/02/29 23:11:55 Document 'template'.
Jacob 2012/03/01 00:40:44 Done.
899 """ 1146 """
1147 self._system = system
900 self._interface = interface 1148 self._interface = interface
901 self._super_interface = super_interface 1149 self._super_interface = super_interface
902 self._dart_code = dart_code 1150 self._dart_code = dart_code
903 self._base_members = base_members 1151 self._base_members = base_members
904 self._current_secondary_parent = None 1152 self._current_secondary_parent = None
1153 self._shared = shared
1154 self._template = template
905 1155
1156 def DomObjectName(self):
1157 return '_documentPtr' if self._interface.id == 'Document' else '_ptr'
1158
1159 # TODO(jacobr): these 3 methods are duplicated.
1160 def _NarrowToImplementationType(self, type_name):
1161 # TODO(sra): Move into the 'system' and cache the result.
1162 if type_name == 'EventListener':
1163 # Callbacks are typedef functions so don't have a class.
1164 return type_name
1165 if self._system._database.HasInterface(type_name):
1166 interface = self._system._database.GetInterface(type_name)
1167 if RecognizeCallback(interface):
1168 # Callbacks are typedef functions so don't have a class.
1169 return type_name
1170 else:
1171 return self._ImplClassName(type_name)
1172 return type_name
1173
1174 def _NarrowInputType(self, type_name):
1175 return self._NarrowToImplementationType(type_name)
1176
1177 def _NarrowOutputType(self, type_name):
1178 return self._NarrowToImplementationType(type_name)
906 1179
907 def StartInterface(self): 1180 def StartInterface(self):
1181
908 interface = self._interface 1182 interface = self._interface
909 interface_name = interface.id 1183 interface_name = interface.id
910
911 self._class_name = self._ImplClassName(interface_name) 1184 self._class_name = self._ImplClassName(interface_name)
912 1185
913 base = self._BaseClassName(interface) 1186 base = None
1187 if interface.parents:
1188 supertype = interface.parents[0].type.id
1189 if not IsDartListType(supertype):
1190 base = self._ImplClassName(supertype)
1191 if IsDartCollectionType(supertype):
1192 # List methods are injected in AddIndexer.
1193 pass
1194 else:
1195 base = self._ImplClassName(supertype)
1196
1197 # TODO(jacobr): this is fragile. There isn't a guarantee that dart:dom
1198 # will continue to exactly match the IDL names.
1199 dom_name = interface.javascript_binding_name
1200 # We hard code the cases for these classes
1201 if dom_name != 'HTMLHtmlElement' and dom_name != 'Document':
1202 self._system._wrap_cases.append(
1203 ' case "%s": return new %s._wrap(domObject);' %
1204 (dom_name, self._class_name))
1205
1206 extends = ' extends ' + base if base else ' extends _DOMTypeBase'
1207
1208 # TODO: Include all implemented interfaces, including other Lists.
1209 implements = [interface_name]
1210 element_type = MaybeTypedArrayElementType(self._interface)
1211 if element_type:
1212 implements.append('List<' + DartType(element_type) + '>')
1213 implements_str = ', '.join(implements)
914 1214
915 (self._members_emitter, 1215 (self._members_emitter,
916 self._top_level_emitter) = self._dart_code.Emit( 1216 self._top_level_emitter) = self._dart_code.Emit(
917 '\n' 1217 self._template + '$!TOP_LEVEL',
918 'class $CLASS extends $BASE implements $INTERFACE {\n' 1218 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
919 ' $CLASS() : super() {}\n' 1219 #$!MEMBERS
920 '\n' 1220 #}
921 ' static create_$CLASS() native {\n' 1221 NATIVESPEC='', # hack to make reusing the same templates work.
922 ' return new $CLASS();\n' 1222 CLASSNAME=self._class_name,
923 ' }\n' 1223 EXTENDS=extends,
924 '$!MEMBERS' 1224 IMPLEMENTS=' implements ' + implements_str)
925 '\n'
926 ' String get typeName() { return "$INTERFACE"; }\n'
927 '}\n'
928 '$!TOP_LEVEL',
929 CLASS=self._class_name, BASE=base, INTERFACE=interface_name)
930 1225
931 def _ImplClassName(self, type_name): 1226 # Document requires a custom wrapper.
932 return '_' + type_name + 'WrappingImplementation' 1227 if dom_name != 'Document':
1228 self._members_emitter.Emit(
1229 ' $(CLASSNAME)._wrap(ptr) : super._wrap(ptr);\n',
1230 CLASSNAME=self._class_name)
933 1231
934 def _BaseClassName(self, interface): 1232 def _BaseClassName(self, interface):
935 if not interface.parents: 1233 if not interface.parents:
936 return 'DOMWrapperBase' 1234 return '_DOMTypeBase'
937 1235
938 supertype = interface.parents[0].type.id 1236 supertype = DartType(interface.parents[0].type.id)
939 1237
940 # FIXME: We're currently injecting List<..> and EventTarget as
941 # supertypes in dart.idl. We should annotate/preserve as
942 # attributes instead. For now, this hack lets the interfaces
943 # inherit, but not the classes.
944 # List methods are injected in AddIndexer.
945 if IsDartListType(supertype) or IsDartCollectionType(supertype): 1238 if IsDartListType(supertype) or IsDartCollectionType(supertype):
946 return 'DOMWrapperBase' 1239 return 'DOMWrapperBase'
947 1240
948 if supertype == 'EventTarget': 1241 if supertype == 'EventTarget':
949 # Most implementors of EventTarget specify the EventListener operations 1242 # Most implementors of EventTarget specify the EventListener operations
950 # again. If the operations are not specified, try to inherit from the 1243 # again. If the operations are not specified, try to inherit from the
951 # EventTarget implementation. 1244 # EventTarget implementation.
952 # 1245 #
953 # Applies to MessagePort. 1246 # Applies to MessagePort.
954 if not [op for op in interface.operations if op.id == 'addEventListener']: 1247 if not [op for op in interface.operations if op.id == 'addEventListener']:
955 return self._ImplClassName(supertype) 1248 return self._ImplClassName(supertype)
956 return 'DOMWrapperBase' 1249 return 'DOMWrapperBase'
957 1250
958 return self._ImplClassName(supertype) 1251 return self._ImplClassName(supertype)
959 1252
1253 def _ImplClassName(self, type_name):
1254 return self._shared._ImplClassName(type_name)
1255
960 def FinishInterface(self): 1256 def FinishInterface(self):
961 """.""" 1257 """."""
962 pass 1258 pass
963 1259
964 def AddConstant(self, constant): 1260 def AddConstant(self, constant):
965 # Constants are already defined on the interface. 1261 # Constants are already defined on the interface.
966 pass 1262 pass
967 1263
968 def _MethodName(self, prefix, name): 1264 def _MethodName(self, prefix, name):
969 method_name = prefix + name 1265 method_name = prefix + name
970 if name in self._base_members: # Avoid illegal Dart 'static override'. 1266 if name in self._base_members: # Avoid illegal Dart 'static override'.
971 method_name = method_name + '_' + self._interface.id 1267 method_name = method_name + '_' + self._interface.id
972 return method_name 1268 return method_name
973 1269
974 def AddAttribute(self, getter, setter): 1270 def AddAttribute(self, getter, setter):
975 if getter: 1271 html_getter_name = self._shared.RenameInHtmlLibrary(
976 self._AddGetter(getter) 1272 self._interface, getter.id, 'get:')
977 if setter: 1273 html_setter_name = self._shared.RenameInHtmlLibrary(
978 self._AddSetter(setter) 1274 self._interface, getter.id, 'set:')
979 1275
980 def _AddGetter(self, attr): 1276 if getter and html_getter_name:
981 # FIXME: Instead of injecting the interface name into the method when it is 1277 self._AddGetter(getter, html_getter_name)
982 # also implemented in the base class, suppress the method altogether if it 1278 if setter and html_setter_name:
983 # has the same signature. I.e., let the JS do the virtual dispatch instead. 1279 self._AddSetter(setter, html_setter_name)
984 method_name = self._MethodName('_get_', attr.id) 1280
1281 def _AddGetter(self, attr, html_name):
1282 if self._shared.MaybeReturnDocument(attr.type.id):
1283 self._members_emitter.Emit(
1284 '\n'
1285 ' $TYPE get $(HTML_NAME)() => '
1286 '_FixHtmlDocumentReference(_wrap($(THIS).$NAME));\n',
1287 NAME=attr.id, HTML_NAME=html_name, TYPE=DartType(attr.type.id),
1288 THIS=self.DomObjectName())
1289 else:
1290 self._members_emitter.Emit(
1291 '\n'
1292 ' $TYPE get $(HTML_NAME)() => _wrap($(THIS).$NAME);\n',
1293 NAME=attr.id, HTML_NAME=html_name, TYPE=DartType(attr.type.id),
1294 THIS=self.DomObjectName())
1295
1296 def _AddSetter(self, attr, html_name):
985 self._members_emitter.Emit( 1297 self._members_emitter.Emit(
986 '\n' 1298 '\n'
987 ' $TYPE get $NAME() { return $METHOD(this); }\n' 1299 ' void set $(HTML_NAME)($TYPE value) { $(THIS).$NAME = _unwrap(value); }\n',
988 ' static $TYPE $METHOD(var _this) native;\n', 1300 NAME=attr.id, HTML_NAME=html_name, TYPE=DartType(attr.type.id),
989 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name) 1301 THIS=self.DomObjectName())
990
991 def _AddSetter(self, attr):
992 # FIXME: See comment on getter.
993 method_name = self._MethodName('_set_', attr.id)
994 self._members_emitter.Emit(
995 '\n'
996 ' void set $NAME($TYPE value) { $METHOD(this, value); }\n'
997 ' static void $METHOD(var _this, $TYPE value) native;\n',
998 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
999 1302
1000 def AddSecondaryAttribute(self, interface, getter, setter): 1303 def AddSecondaryAttribute(self, interface, getter, setter):
1001 self._SecondaryContext(interface) 1304 self._SecondaryContext(interface)
1002 self.AddAttribute(getter, setter) 1305 self.AddAttribute(getter, setter)
1003 1306
1004 def AddSecondaryOperation(self, interface, info): 1307 def AddSecondaryOperation(self, interface, info):
1005 self._SecondaryContext(interface) 1308 self._SecondaryContext(interface)
1006 self.AddOperation(info) 1309 self.AddOperation(info)
1007 1310
1008 def AddEventAttributes(self, event_attrs): 1311 def AddEventAttributes(self, event_attrs):
1009 pass 1312 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
1313 events_class = '_' + self._interface.id + 'EventsImpl'
1314 events_interface = self._interface.id + 'Events'
1315 self._members_emitter.Emit(
1316 '\n'
1317 ' $TYPE get on() {\n'
1318 ' if (_on == null) _on = new $TYPE($EVENTTARGET);\n'
1319 ' return _on;\n'
1320 ' }\n',
1321 TYPE=events_class,
1322 EVENTTARGET='_wrappedDocumentPtr' if self._interface.id == 'Document'
1323 else 'this')
1324
1325 self._shared._event_classes.add(self._interface.id)
1326
1327 parent_event_classes = self._shared.GetParentsEventsClasses(
1328 self._interface)
1329 if len(parent_event_classes) != 1:
1330 raise Exception('Only one parent event class allowed '
1331 + self._interface.id)
1332
1333 # TODO(jacobr): specify the type of _ptr as EventTarget
1334 events_members = self._dart_code.Emit(
1335 '\n'
1336 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
1337 ' $CLASSNAME(_ptr) : super(_ptr);\n'
1338 '$!MEMBERS}\n',
1339 TARGETCLASS=self._NarrowOutputType(self._interface.id),
sra1 2012/02/29 23:11:55 TARGETCLASS appears to be unused.
Jacob 2012/03/01 00:40:44 Done.
1340 CLASSNAME=events_class,
1341 INTERFACE=events_interface,
1342 SUPER='_' + parent_event_classes[0] + 'Impl')
1343
1344 for event_name in event_attrs:
1345 if event_name in _html_event_names:
1346 events_members.Emit(
1347 "\n"
1348 " EventListenerList get $NAME() => _get('$RAWNAME');\n",
1349 RAWNAME=event_name,
1350 NAME=_html_event_names[event_name])
1351 else:
1352 raise Exception('No known html even name for event: ' + event_name)
1010 1353
1011 def _SecondaryContext(self, interface): 1354 def _SecondaryContext(self, interface):
1012 if interface is not self._current_secondary_parent: 1355 if interface is not self._current_secondary_parent:
1013 self._current_secondary_parent = interface 1356 self._current_secondary_parent = interface
1014 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) 1357 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id)
1015 1358
1359 # TODO(jacobr): change this to more directly match the frog version.
1016 def AddIndexer(self, element_type): 1360 def AddIndexer(self, element_type):
1017 """Adds all the methods required to complete implementation of List.""" 1361 """Adds all the methods required to complete implementation of List."""
1018 # We would like to simply inherit the implementation of everything except 1362 # We would like to simply inherit the implementation of everything except
1019 # get length(), [], and maybe []=. It is possible to extend from a base 1363 # get length(), [], and maybe []=. It is possible to extend from a base
1020 # array implementation class only when there is no other implementation 1364 # array implementation class only when there is no other implementation
1021 # inheritance. There might be no implementation inheritance other than 1365 # inheritance. There might be no implementation inheritance other than
1022 # DOMBaseWrapper for many classes, but there might be some where the 1366 # DOMBaseWrapper for many classes, but there might be some where the
1023 # array-ness is introduced by a non-root interface: 1367 # array-ness is introduced by a non-root interface:
1024 # 1368 #
1025 # interface Y extends X, List<T> ... 1369 # interface Y extends X, List<T> ...
1026 # 1370 #
1027 # In the non-root case we have to choose between: 1371 # In the non-root case we have to choose between:
1028 # 1372 #
1029 # class YImpl extends XImpl { add List<T> methods; } 1373 # class YImpl extends XImpl { add List<T> methods; }
1030 # 1374 #
1031 # and 1375 # and
1032 # 1376 #
1033 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } 1377 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
1034 # 1378 #
1035 if self._HasNativeIndexGetter(self._interface): 1379 if self._HasNativeIndexGetter(self._interface):
1036 self._EmitNativeIndexGetter(self._interface, element_type) 1380 self._EmitNativeIndexGetter(self._interface, element_type)
1037 else: 1381 else:
1038 self._members_emitter.Emit( 1382 self._members_emitter.Emit(
1039 '\n' 1383 '\n'
1040 ' $TYPE operator[](int index) {\n' 1384 ' $TYPE operator[](int index) => _wrap($(THIS)[index]);\n'
1041 ' return item(index);\n' 1385 '\n',
1042 ' }\n', 1386 THIS=self.DomObjectName(),
1043 TYPE=DartType(element_type)) 1387 TYPE=DartType(element_type))
1044 1388
1045 if self._HasNativeIndexSetter(self._interface): 1389 if self._HasNativeIndexSetter(self._interface):
1046 self._EmitNativeIndexSetter(self._interface, element_type) 1390 self._EmitNativeIndexSetter(self._interface, element_type)
1047 else: 1391 else:
1048 self._members_emitter.Emit( 1392 # The HTML library implementation of NodeList has a custom indexed setter
1049 '\n' 1393 # implementation that uses the parent node the NodeList is associated
1050 ' void operator[]=(int index, $TYPE value) {\n' 1394 # with if one is available.
1051 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n' 1395 if self._interface.id != 'NodeList':
1052 ' }\n', 1396 self._members_emitter.Emit(
1053 TYPE=element_type) 1397 '\n'
1398 ' void operator[]=(int index, $TYPE value) {\n'
1399 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
1400 ' }\n',
1401 TYPE=DartType(element_type))
1402
1403 # The list interface for this class is manually generated.
1404 if self._interface.id == 'NodeList':
1405 return
1054 1406
1055 self._members_emitter.Emit( 1407 self._members_emitter.Emit(
1056 '\n' 1408 '\n'
1057 ' void add($TYPE value) {\n' 1409 ' void add($TYPE value) {\n'
1058 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n' 1410 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1059 ' }\n' 1411 ' }\n'
1060 '\n' 1412 '\n'
1061 ' void addLast($TYPE value) {\n' 1413 ' void addLast($TYPE value) {\n'
1062 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n' 1414 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1063 ' }\n' 1415 ' }\n'
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1132 ' throw new NotImplementedException();\n' 1484 ' throw new NotImplementedException();\n'
1133 ' }\n' 1485 ' }\n'
1134 '\n' 1486 '\n'
1135 ' bool isEmpty() {\n' 1487 ' bool isEmpty() {\n'
1136 ' return length == 0;\n' 1488 ' return length == 0;\n'
1137 ' }\n' 1489 ' }\n'
1138 '\n' 1490 '\n'
1139 ' Iterator<$TYPE> iterator() {\n' 1491 ' Iterator<$TYPE> iterator() {\n'
1140 ' return new _FixedSizeListIterator<$TYPE>(this);\n' 1492 ' return new _FixedSizeListIterator<$TYPE>(this);\n'
1141 ' }\n', 1493 ' }\n',
1142 TYPE=element_type) 1494 TYPE=DartType(element_type))
1143 1495
1144 def _HasNativeIndexGetter(self, interface): 1496 def _HasNativeIndexGetter(self, interface):
1145 return ('HasIndexGetter' in interface.ext_attrs or 1497 return ('HasIndexGetter' in interface.ext_attrs or
1146 'HasNumericIndexGetter' in interface.ext_attrs) 1498 'HasNumericIndexGetter' in interface.ext_attrs)
1147 1499
1148 def _EmitNativeIndexGetter(self, interface, element_type): 1500 def _EmitNativeIndexGetter(self, interface, element_type):
1149 method_name = '_index' 1501 method_name = '_index'
1150 self._members_emitter.Emit( 1502 self._members_emitter.Emit(
1151 '\n' 1503 '\n $TYPE operator[](int index) => _wrap($(THIS)[index]);\n',
1152 ' $TYPE operator[](int index) { return $METHOD(this, index); }\n' 1504 TYPE=DartType(element_type), THIS=self.DomObjectName(), METHOD=method_na me)
1153 ' static $TYPE $METHOD(var _this, int index) native;\n',
1154 TYPE=element_type, METHOD=method_name)
1155 1505
1156 def _HasNativeIndexSetter(self, interface): 1506 def _HasNativeIndexSetter(self, interface):
1157 return 'HasCustomIndexSetter' in interface.ext_attrs 1507 return 'HasCustomIndexSetter' in interface.ext_attrs
1158 1508
1159 def _EmitNativeIndexSetter(self, interface, element_type): 1509 def _EmitNativeIndexSetter(self, interface, element_type):
1160 method_name = '_set_index' 1510 method_name = '_set_index'
1161 self._members_emitter.Emit( 1511 self._members_emitter.Emit(
1162 '\n' 1512 '\n'
1163 ' void operator[]=(int index, $TYPE value) {\n' 1513 ' void operator[]=(int index, $TYPE value) {\n'
1164 ' return $METHOD(this, index, value);\n' 1514 ' return $(THIS)[index] = _unwrap(value);\n'
1165 ' }\n' 1515 ' }\n',
1166 ' static $METHOD(_this, index, value) native;\n', 1516 THIS=self.DomObjectName(), TYPE=DartType(element_type), METHOD=method_na me)
1167 TYPE=element_type, METHOD=method_name)
1168 1517
1169 def AddOperation(self, info): 1518 def AddOperation(self, info):
1170 """ 1519 """
1171 Arguments: 1520 Arguments:
1172 info: An OperationInfo object. 1521 info: An OperationInfo object.
1173 """ 1522 """
1523 html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
1524
1525 if not html_name:
1526 return
1527
1174 body = self._members_emitter.Emit( 1528 body = self._members_emitter.Emit(
1175 '\n' 1529 '\n'
1176 ' $TYPE $NAME($PARAMS) {\n' 1530 ' $TYPE $HTML_NAME($PARAMS) {\n'
1177 '$!BODY' 1531 '$!BODY'
1178 ' }\n', 1532 ' }\n',
1179 TYPE=info.type_name, 1533 TYPE=info.type_name,
1180 NAME=info.name, 1534 HTML_NAME=html_name,
1181 PARAMS=info.ParametersImplementationDeclaration()) 1535 PARAMS=info.ParametersImplementationDeclaration())
1182 1536
1183 # Process in order of ascending number of arguments to ensure missing 1537 # Process in order of ascending number of arguments to ensure missing
1184 # optional arguments are processed early. 1538 # optional arguments are processed early.
1185 overloads = sorted(info.overloads, 1539 overloads = sorted(info.overloads,
1186 key=lambda overload: len(overload.arguments)) 1540 key=lambda overload: len(overload.arguments))
1187 self._native_version = 0 1541 self._native_version = 0
1188 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) 1542 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads)
1189 if fallthrough: 1543 if fallthrough:
1190 body.Emit(' throw "Incorrect number or type of arguments";\n'); 1544 body.Emit(' throw "Incorrect number or type of arguments";\n');
1191 1545
1192 def GenerateSingleOperation(self, emitter, info, indent, operation): 1546 def GenerateSingleOperation(self, emitter, info, indent, operation):
1193 """Generates a call to a single operation. 1547 """Generates a call to a single operation.
1194 1548
1195 Arguments: 1549 Arguments:
1196 emitter: an Emitter for the body of a block of code. 1550 emitter: an Emitter for the body of a block of code.
1197 info: the compound information about the operation and its overloads. 1551 info: the compound information about the operation and its overloads.
1198 indent: an indentation string for generated code. 1552 indent: an indentation string for generated code.
1199 operation: the IDLOperation to call. 1553 operation: the IDLOperation to call.
1200 """ 1554 """
1201 # TODO(sra): Do we need to distinguish calling with missing optional 1555 # TODO(sra): Do we need to distinguish calling with missing optional
1202 # arguments from passing 'null' which is represented as 'undefined'? 1556 # arguments from passing 'null' which is represented as 'undefined'?
1203 def UnwrapArgExpression(name, type): 1557 def UnwrapArgExpression(name, type):
1204 # TODO: Type specific unwrapping. 1558 # TODO: Type specific unwrapping.
1205 return '__dom_unwrap(%s)' % (name) 1559 return '_unwrap(%s)' % (name)
1206 1560
1207 def ArgNameAndUnwrapper(arg_info, overload_arg): 1561 def ArgNameAndUnwrapper(arg_info, overload_arg):
1208 (name, type, value) = arg_info 1562 (name, type, value) = arg_info
1209 return (name, UnwrapArgExpression(name, type)) 1563 return (name, UnwrapArgExpression(name, type))
1210 1564
1211 names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg) 1565 names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg)
1212 for (i, arg) in enumerate(operation.arguments)] 1566 for (i, arg) in enumerate(operation.arguments)]
1213 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers] 1567 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers]
1214 arg_names = [name for (name, _) in names_and_unwrappers] 1568 arg_names = ['_unwrap(%s)' % name for (name, _) in names_and_unwrappers]
1215 1569
1216 self._native_version += 1 1570 argument_expressions = ', '.join(arg_names)
1217 native_name = self._MethodName('_', info.name)
1218 if self._native_version > 1:
1219 native_name = '%s_%s' % (native_name, self._native_version)
1220
1221 argument_expressions = ', '.join(['this'] + arg_names)
1222 if info.type_name != 'void': 1571 if info.type_name != 'void':
1223 emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n', 1572 # We could place the logic for handling Document directly in _wrap
1224 INDENT=indent, 1573 # but we chose to place it here so that bugs in the wrapper and
1225 NATIVENAME=native_name, 1574 # wrapperless implementations are more consistent.
1226 ARGS=argument_expressions) 1575 if self._shared.MaybeReturnDocument(info.type_name):
1576 emitter.Emit('$(INDENT)return _FixHtmlDocumentReference('
1577 '_wrap($(THIS).$NAME($ARGS)));\n',
1578 INDENT=indent,
1579 THIS=self.DomObjectName(),
1580 NAME=info.name,
1581 ARGS=argument_expressions)
1582 else:
1583 emitter.Emit('$(INDENT)return _wrap($(THIS).$NAME($ARGS));\n',
1584 INDENT=indent,
1585 THIS=self.DomObjectName(),
1586 NAME=info.name,
1587 ARGS=argument_expressions)
1227 else: 1588 else:
1228 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n' 1589 emitter.Emit('$(INDENT)$(THIS).$NAME($ARGS);\n'
1229 '$(INDENT)return;\n', 1590 '$(INDENT)return;\n',
1230 INDENT=indent, 1591 INDENT=indent,
1231 NATIVENAME=native_name, 1592 THIS=self.DomObjectName(),
1593 NAME=info.name,
1232 ARGS=argument_expressions) 1594 ARGS=argument_expressions)
1233 1595
1234 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n',
1235 NAME=native_name,
1236 TYPE=info.type_name,
1237 PARAMS=', '.join(['receiver'] + arg_names) )
1238
1239
1240 def GenerateDispatch(self, emitter, info, indent, position, overloads): 1596 def GenerateDispatch(self, emitter, info, indent, position, overloads):
1241 """Generates a dispatch to one of the overloads. 1597 """Generates a dispatch to one of the overloads.
1242 1598
1243 Arguments: 1599 Arguments:
1244 emitter: an Emitter for the body of a block of code. 1600 emitter: an Emitter for the body of a block of code.
1245 info: the compound information about the operation and its overloads. 1601 info: the compound information about the operation and its overloads.
1246 indent: an indentation string for generated code. 1602 indent: an indentation string for generated code.
1247 position: the index of the parameter to dispatch on. 1603 position: the index of the parameter to dispatch on.
1248 overloads: a list of the remaining IDLOperations to dispatch. 1604 overloads: a list of the remaining IDLOperations to dispatch.
1249 1605
(...skipping 22 matching lines...) Expand all
1272 positive = [] 1628 positive = []
1273 negative = [] 1629 negative = []
1274 first_overload = overloads[0] 1630 first_overload = overloads[0]
1275 (param_name, param_type, param_default) = info.arg_infos[position] 1631 (param_name, param_type, param_default) = info.arg_infos[position]
1276 1632
1277 if position < len(first_overload.arguments): 1633 if position < len(first_overload.arguments):
1278 # FIXME: This will not work if the second overload has a more 1634 # FIXME: This will not work if the second overload has a more
1279 # precise type than the first. E.g., 1635 # precise type than the first. E.g.,
1280 # void foo(Node x); 1636 # void foo(Node x);
1281 # void foo(Element x); 1637 # void foo(Element x);
1282 type = first_overload.arguments[position].type.id 1638 type = DartType(first_overload.arguments[position].type.id)
1283 test = TypeCheck(param_name, type) 1639 test = TypeCheck(param_name, type)
1284 pred = lambda op: len(op.arguments) > position and op.arguments[position]. type.id == type 1640 pred = lambda op: (len(op.arguments) > position and
1641 DartType(op.arguments[position].type.id) == type)
1285 else: 1642 else:
1286 type = None 1643 type = None
1287 test = NullCheck(param_name) 1644 test = NullCheck(param_name)
1288 pred = lambda op: position >= len(op.arguments) 1645 pred = lambda op: position >= len(op.arguments)
1289 1646
1290 for overload in overloads: 1647 for overload in overloads:
1291 if pred(overload): 1648 if pred(overload):
1292 positive.append(overload) 1649 positive.append(overload)
1293 else: 1650 else:
1294 negative.append(overload) 1651 negative.append(overload)
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1326 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee 1683 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee
1327 # that Y = Z-X, so we need to check for Y. 1684 # that Y = Z-X, so we need to check for Y.
1328 true_code = emitter.Emit( 1685 true_code = emitter.Emit(
1329 '$(INDENT)if ($COND) {\n' 1686 '$(INDENT)if ($COND) {\n'
1330 '$!TRUE' 1687 '$!TRUE'
1331 '$(INDENT)}\n', 1688 '$(INDENT)}\n',
1332 COND=test, INDENT=indent) 1689 COND=test, INDENT=indent)
1333 self.GenerateDispatch( 1690 self.GenerateDispatch(
1334 true_code, info, indent + ' ', position + 1, positive) 1691 true_code, info, indent + ' ', position + 1, positive)
1335 return True 1692 return True
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698