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

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

Issue 9845043: Rename client/{dom,html} to lib/{dom,html} . (Closed) Base URL: http://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
« no previous file with comments | « client/dom/scripts/systemfrog.py ('k') | client/dom/scripts/systeminterface.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
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
4 # BSD-style license that can be found in the LICENSE file.
5
6 """This module provides shared functionality for the system to generate
7 Dart:html APIs from the IDL database."""
8
9 from systemfrog import *
10 from systeminterface import *
11
12 # Members from the standard dom that should not be exposed publicly in dart:html
13 # but need to be exposed internally to implement dart:html on top of a standard
14 # browser.
15 _private_html_members = set([
16 'Element.clientLeft',
17 'Element.clientTop',
18 'Element.clientWidth',
19 'Element.clientHeight',
20 'Element.offsetLeft',
21 'Element.offsetTop',
22 'Element.offsetWidth',
23 'Element.offsetHeight',
24 'Element.scrollLeft',
25 'Element.scrollTop',
26 'Element.scrollWidth',
27 'Element.scrollHeight',
28 'Element.childElementCount',
29 'Element.firstElementChild',
30 'Element.hasAttribute',
31 'Element.getAttribute',
32 'Element.removeAttribute',
33 'Element.setAttribute',
34 'Element.className',
35 'Element.children',
36 'Element.querySelectorAll',
37 'NodeSelector.querySelectorAll',
38 'Document.querySelectorAll',
39 'DocumentFragment.querySelectorAll',
40 'Element.getBoundingClientRect',
41 'Element.getClientRects',
42 'Node.appendChild',
43 'Node.removeChild',
44 'Node.replaceChild',
45 'Node.attributes',
46 'Node.childNodes',
47 'Document.createElement',
48 'Document.createElementNS',
49 'Document.createEvent',
50 'Document.createTextNode',
51 'Document.createTouchList',
52 'Window.getComputedStyle',
53 'EventTarget.removeEventListener',
54 'EventTarget.addEventListener',
55 'EventTarget.dispatchEvent',
56 'Event.initEvent',
57 'MouseEvent.initMouseEvent',
58 ])
59
60 # Members from the standard dom that exist in the dart:html library with
61 # identical functionality but with cleaner names.
62 _html_library_renames = {
63 'Document.defaultView': 'window',
64 'DocumentFragment.querySelector': 'query',
65 'NodeSelector.querySelector': 'query',
66 'Element.querySelector': 'query',
67 'Element.webkitMatchesSelector' : 'matchesSelector',
68 'Element.scrollIntoViewIfNeeded': 'scrollIntoView',
69 'Document.querySelector': 'query',
70 'Node.cloneNode': 'clone',
71 'Node.nextSibling': 'nextNode',
72 'Node.ownerDocument': 'document',
73 'Node.parentNode': 'parent',
74 'Node.previousSibling': 'previousNode',
75 'Node.textContent': 'text',
76 'SVGElement.className': '_svgClassName',
77 'SVGAnimatedString.className': '_svgClassName',
78 'SVGStylable.className': '_svgClassName',
79 }
80
81 #TODO(jacobr): inject annotations into the interfaces based on this table and
82 # on _html_library_renames.
83 _injected_doc_fragments = {
84 'Element.query': ' /** @domName querySelector, Document.getElementById */',
85 }
86 # Members and classes from the dom that should be removed completelly from
87 # dart:html. These could be expressed in the IDL instead but expressing this
88 # as a simple table instead is more concise.
89 # Syntax is: ClassName.(get\.|set\.)?MemberName
90 # Using get: and set: is optional and should only be used when a getter needs
91 # to be suppressed but not the setter, etc.
92 # TODO(jacobr): cleanup and augment this list.
93 _html_library_remove = set([
94 'Window.get:document', # Removed as we have a custom implementation.
95 'NodeList.item',
96 "Attr.*",
97 # "BarProp.*",
98 # "BarInfo.*",
99 # "Blob.webkitSlice",
100 # "CDATASection.*",
101 # "Comment.*",
102 # "DOMImplementation.*",
103 "Document.get:documentElement",
104 "Document.get:forms",
105 # "Document.get:selectedStylesheetSet",
106 # "Document.set:selectedStylesheetSet",
107 # "Document.get:preferredStylesheetSet",
108 "Document.get:links",
109 "Document.getElementsByTagName",
110 "Document.set:domain",
111 "Document.get:implementation",
112 "Document.createAttributeNS",
113 "Document.get:inputEncoding",
114 "Document.getElementById",
115 "Document.getElementsByClassName",
116 "Document.get:height",
117 "Document.get:width",
118 "Element.getElementsByClassName",
119 "Element.getElementsByTagNameNS",
120 "Element.getElementsByTagName",
121 "Document.get:compatMode",
122 "Document.importNode",
123 "Document.evaluate",
124 "Document.get:images",
125 "Document.querySelector",
126 "Document.createExpression",
127 "Document.getOverrideStyle",
128 "Document.xmlStandalone",
129 "Document.createComment",
130 "Document.adoptNode",
131 "Document.get:characterSet",
132 "Document.createAttribute",
133 "Document.querySelectorAll",
134 "Document.get:URL",
135 "Document.createEntityReference",
136 "Document.get:documentURI",
137 "Document.set:documentURI",
138 "Document.createNodeIterator",
139 "Document.createProcessingInstruction",
140 "Document.get:doctype",
141 "Document.getElementsByName",
142 "Document.createTreeWalker",
143 "Document.location",
144 "Document.createNSResolver",
145 "Document.get:xmlEncoding",
146 "Document.get:defaultCharset",
147 "Document.get:applets",
148 "Document.getSelection",
149 "Document.xmlVersion",
150 "Document.get:anchors",
151 "Document.getElementsByTagNameNS",
152 "DocumentType.*",
153 "Element.hasAttributeNS",
154 "Element.getAttributeNS",
155 "Element.setAttributeNode",
156 "Element.getAttributeNode",
157 "Element.removeAttributeNode",
158 "Element.removeAttributeNS",
159 "Element.setAttributeNodeNS",
160 "Element.getAttributeNodeNS",
161 "Element.setAttributeNS",
162 "BodyElement.text",
163 "AnchorElement.text",
164 "OptionElement.text",
165 "ScriptElement.text",
166 "TitleElement.text",
167 # "EventSource.get:url",
168 # TODO(jacobr): should these be removed?
169 "Document.close",
170 "Document.hasFocus",
171
172 "Document.vlinkColor",
173 "Document.captureEvents",
174 "Document.releaseEvents",
175 "Document.get:compatMode",
176 "Document.designMode",
177 "Document.dir",
178 "Document.all",
179 "Document.write",
180 "Document.fgColor",
181 "Document.bgColor",
182 "Document.get:plugins",
183 "Document.alinkColor",
184 "Document.get:embeds",
185 "Document.open",
186 "Document.clear",
187 "Document.get:scripts",
188 "Document.writeln",
189 "Document.linkColor",
190 "Element.get:itemRef",
191 "Element.outerText",
192 "Element.accessKey",
193 "Element.get:itemType",
194 "Element.innerText",
195 "Element.set:outerHTML",
196 "Element.itemScope",
197 "Element.itemValue",
198 "Element.itemId",
199 "Element.get:itemProp",
200 'Element.scrollIntoView',
201 'Element.get:classList',
202 "EmbedElement.getSVGDocument",
203 "FormElement.get:elements",
204 "HTMLFrameElement.*",
205 "HTMLFrameSetElement.*",
206 "HtmlElement.version",
207 "HtmlElement.manifest",
208 "Document.version",
209 "Document.manifest",
210 # "IFrameElement.getSVGDocument", #TODO(jacobr): should this be removed
211 "InputElement.dirName",
212 "HTMLIsIndexElement.*",
213 "ObjectElement.getSVGDocument",
214 "HTMLOptionsCollection.*",
215 "HTMLPropertiesCollection.*",
216 "SelectElement.remove",
217 "TextAreaElement.dirName",
218 "NamedNodeMap.*",
219 "Node.isEqualNode",
220 "Node.get:TEXT_NODE",
221 "Node.hasAttributes",
222 "Node.get:DOCUMENT_TYPE_NODE",
223 "Node.get:DOCUMENT_POSITION_FOLLOWING",
224 "Node.lookupNamespaceURI",
225 "Node.get:ELEMENT_NODE",
226 "Node.get:namespaceURI",
227 "Node.get:DOCUMENT_FRAGMENT_NODE",
228 "Node.get:localName",
229 "Node.dispatchEvent",
230 "Node.isDefaultNamespace",
231 "Node.compareDocumentPosition",
232 "Node.get:baseURI",
233 "Node.isSameNode",
234 "Node.get:DOCUMENT_POSITION_DISCONNECTED",
235 "Node.get:DOCUMENT_NODE",
236 "Node.get:DOCUMENT_POSITION_CONTAINS",
237 "Node.get:COMMENT_NODE",
238 "Node.get:ENTITY_REFERENCE_NODE",
239 "Node.isSupported",
240 "Node.get:firstChild",
241 "Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC",
242 "Node.get:lastChild",
243 "Node.get:NOTATION_NODE",
244 "Node.normalize",
245 "Node.get:parentElement",
246 "Node.get:ATTRIBUTE_NODE",
247 "Node.get:ENTITY_NODE",
248 "Node.get:DOCUMENT_POSITION_CONTAINED_BY",
249 "Node.get:prefix",
250 "Node.set:prefix",
251 "Node.get:DOCUMENT_POSITION_PRECEDING",
252 "Node.get:nodeType",
253 "Node.removeEventListener",
254 "Node.get:nodeValue",
255 "Node.set:nodeValue",
256 "Node.get:CDATA_SECTION_NODE",
257 "Node.get:nodeName",
258 "Node.addEventListener",
259 "Node.lookupPrefix",
260 "Node.get:PROCESSING_INSTRUCTION_NODE",
261 "Notification.dispatchEvent",
262 "Notification.addEventListener",
263 "Notification.removeEventListener"])
264
265 # Events without onEventName attributes in the IDL we want to support.
266 # We can automatically extract most event event names by checking for
267 # onEventName methods in the IDL but some events aren't listed so we need
268 # to manually add them here so that they are easy for users to find.
269 _html_manual_events = {
270 'Element': ['touchleave', 'webkitTransitionEnd'],
271 'Window': ['DOMContentLoaded']
272 }
273
274 # These event names must be camel case when attaching event listeners
275 # using addEventListener even though the onEventName properties in the DOM for
276 # them are not camel case.
277 _on_attribute_to_event_name_mapping = {
278 'webkitanimationend': 'webkitAnimationEnd',
279 'webkitanimationiteration': 'webkitAnimationIteration',
280 'webkitanimationstart': 'webkitAnimationStart',
281 'webkitspeechchange': 'webkitSpeechChange',
282 'webkittransitionend': 'webkitTransitionEnd',
283 }
284
285 # Mapping from raw event names to the pretty camelCase event names exposed as
286 # properties in dart:html. If the DOM exposes a new event name, you will need
287 # to add the lower case to camel case conversion for that event name here.
288 _html_event_names = {
289 'DOMContentLoaded': 'contentLoaded',
290 'touchleave': 'touchLeave',
291 'abort': 'abort',
292 'beforecopy': 'beforeCopy',
293 'beforecut': 'beforeCut',
294 'beforepaste': 'beforePaste',
295 'beforeunload': 'beforeUnload',
296 'blur': 'blur',
297 'cached': 'cached',
298 'canplay': 'canPlay',
299 'canplaythrough': 'canPlayThrough',
300 'change': 'change',
301 'checking': 'checking',
302 'click': 'click',
303 'close': 'close',
304 'contextmenu': 'contextMenu',
305 'copy': 'copy',
306 'cut': 'cut',
307 'dblclick': 'doubleClick',
308 'devicemotion': 'deviceMotion',
309 'deviceorientation': 'deviceOrientation',
310 'display': 'display',
311 'downloading': 'downloading',
312 'drag': 'drag',
313 'dragend': 'dragEnd',
314 'dragenter': 'dragEnter',
315 'dragleave': 'dragLeave',
316 'dragover': 'dragOver',
317 'dragstart': 'dragStart',
318 'drop': 'drop',
319 'durationchange': 'durationChange',
320 'emptied': 'emptied',
321 'ended': 'ended',
322 'error': 'error',
323 'focus': 'focus',
324 'hashchange': 'hashChange',
325 'input': 'input',
326 'invalid': 'invalid',
327 'keydown': 'keyDown',
328 'keypress': 'keyPress',
329 'keyup': 'keyUp',
330 'load': 'load',
331 'loadeddata': 'loadedData',
332 'loadedmetadata': 'loadedMetadata',
333 'loadend': 'loadEnd',
334 'loadstart': 'loadStart',
335 'message': 'message',
336 'mousedown': 'mouseDown',
337 'mousemove': 'mouseMove',
338 'mouseout': 'mouseOut',
339 'mouseover': 'mouseOver',
340 'mouseup': 'mouseUp',
341 'mousewheel': 'mouseWheel',
342 'noupdate': 'noUpdate',
343 'obsolete': 'obsolete',
344 'offline': 'offline',
345 'online': 'online',
346 'open': 'open',
347 'pagehide': 'pageHide',
348 'pageshow': 'pageShow',
349 'paste': 'paste',
350 'pause': 'pause',
351 'play': 'play',
352 'playing': 'playing',
353 'popstate': 'popState',
354 'progress': 'progress',
355 'ratechange': 'rateChange',
356 'readystatechange': 'readyStateChange',
357 'reset': 'reset',
358 'resize': 'resize',
359 'scroll': 'scroll',
360 'search': 'search',
361 'seeked': 'seeked',
362 'seeking': 'seeking',
363 'select': 'select',
364 'selectionchange': 'selectionChange',
365 'selectstart': 'selectStart',
366 'show': 'show',
367 'stalled': 'stalled',
368 'storage': 'storage',
369 'submit': 'submit',
370 'suspend': 'suspend',
371 'timeupdate': 'timeUpdate',
372 'touchcancel': 'touchCancel',
373 'touchend': 'touchEnd',
374 'touchmove': 'touchMove',
375 'touchstart': 'touchStart',
376 'unload': 'unload',
377 'updateready': 'updateReady',
378 'volumechange': 'volumeChange',
379 'waiting': 'waiting',
380 'webkitAnimationEnd': 'animationEnd',
381 'webkitAnimationIteration': 'animationIteration',
382 'webkitAnimationStart': 'animationStart',
383 'webkitfullscreenchange': 'fullscreenChange',
384 'webkitfullscreenerror': 'fullscreenError',
385 'webkitSpeechChange': 'speechChange',
386 'webkitTransitionEnd': 'transitionEnd'
387 }
388
389 # These classes require an explicit declaration for the "on" method even though
390 # they don't declare any unique events, because the concrete class hierarchy
391 # doesn't match the interface hierarchy.
392 _html_explicit_event_classes = set(['DocumentFragment'])
393
394 def _OnAttributeToEventName(on_method):
395 event_name = on_method.id[2:]
396 if event_name in _on_attribute_to_event_name_mapping:
397 return _on_attribute_to_event_name_mapping[event_name]
398 else:
399 return event_name
400
401 def _DomToHtmlEvents(interface_id, events):
402 event_names = set(map(_OnAttributeToEventName, events))
403 if interface_id in _html_manual_events:
404 for manual_event_name in _html_manual_events[interface_id]:
405 event_names.add(manual_event_name)
406
407 return sorted(event_names, key=lambda name: _html_event_names[name])
408
409 # ------------------------------------------------------------------------------
410 class HtmlSystemShared(object):
411
412 def __init__(self, database, generator):
413 self._event_classes = set()
414 self._seen_event_names = {}
415 self._database = database
416 self._generator = generator
417
418 def _AllowInHtmlLibrary(self, interface, member, member_prefix):
419 return not self._Matches(interface, member, member_prefix,
420 _html_library_remove)
421
422 def _Matches(self, interface, member, member_prefix, candidates):
423 for interface_name in self._AllAncestorInterfaces(interface):
424 if (DartType(interface_name) + '.' + member in candidates or
425 DartType(interface_name) + '.' + member_prefix + member in candidates) :
426 return True
427 return False
428
429 def MaybeReturnDocument(self, return_type):
430 """
431 To make it appear that there are not a distinct Document and
432 HTMLHtmlElement (document.documentElement) objects we always use
433 documentElement instead of the regular document object so must not
434 allow a regular document to leak out.
435 """
436 # TODO(jacobr): any method that returns a Node could also theoretically
437 # really return a Document but there are alot of methods that return nodes
438 # and they all appear to be safe. Consider the alternate strategy of
439 # whitelisting just the known safe methods that return Nodes.
440 return (DartType(return_type) == 'EventTarget' or
441 DartType(return_type) == 'Document')
442
443 def _AllAncestorInterfaces(self, interface):
444 interfaces = ([interface.id] +
445 self._generator._AllImplementedInterfaces(interface))
446 return interfaces
447
448 def RenameInHtmlLibrary(self, interface, member, member_prefix=''):
449 """
450 Returns the name of the member in the HTML library or None if the member is
451 suppressed in the HTML library
452 """
453 if not self._AllowInHtmlLibrary(interface, member, member_prefix):
454 return None
455
456 for interface_name in self._AllAncestorInterfaces(interface):
457 name = interface_name + '.' + member
458 if name in _html_library_renames:
459 return _html_library_renames[name]
460 name = interface.id + '.' + member_prefix + member
461 if name in _html_library_renames:
462 return _html_library_renames[name]
463
464 if self._PrivateInHtmlLibrary(interface, member, member_prefix):
465 return '_' + member
466
467 # No rename required
468 return member
469
470 def _PrivateInHtmlLibrary(self, interface, member, member_prefix):
471 return self._Matches(interface, member, member_prefix,
472 _private_html_members)
473
474 # TODO(jacobr): this already exists
475 def _TraverseParents(self, interface, callback):
476 for parent in interface.parents:
477 parent_id = parent.type.id
478 if self._database.HasInterface(parent_id):
479 parent_interface = self._database.GetInterface(parent_id)
480 callback(parent_interface)
481 self._TraverseParents(parent_interface, callback)
482
483 # TODO(jacobr): this isn't quite right....
484 def GetParentsEventsClasses(self, interface):
485 # Ugly hack as we don't specify that Document and DocumentFragment inherit
486 # from Element in our IDL.
487 if interface.id == 'Document' or interface.id == 'DocumentFragment':
488 return ['ElementEvents']
489
490 interfaces_with_events = set()
491 def visit(parent):
492 if parent.id in self._event_classes:
493 interfaces_with_events.add(parent)
494
495 self._TraverseParents(interface, visit)
496 if len(interfaces_with_events) == 0:
497 return ['Events']
498 else:
499 names = []
500 for interface in interfaces_with_events:
501 names.append(interface.id + 'Events')
502 return names
503
504 def GetParentEventsClass(self, interface):
505 parent_event_classes = self.GetParentsEventsClasses(interface)
506 if len(parent_event_classes) != 1:
507 raise Exception('Only one parent event class allowed ' + interface.id)
508 return parent_event_classes[0]
509
510 def _ImplClassName(self, type_name):
511 return '_' + type_name + 'Impl'
512
513 # This returns two values: the first is whether or not an "on" property should
514 # be generated for the interface, and the second is the event attributes to
515 # generate if it should.
516 def GetEventAttributes(self, interface):
517 events = set([attr for attr in interface.attributes
518 if self._generator._IsEventAttribute(interface, attr)])
519
520 if events or interface.id in _html_explicit_event_classes:
521 return True, events
522 else:
523 return False, None
524
525 def IsPrivate(self, name):
526 return name.startswith('_')
527
528 class HtmlSystem(System):
529
530 def __init__(self, templates, database, emitters, output_dir, generator):
531 super(HtmlSystem, self).__init__(
532 templates, database, emitters, output_dir)
533 self._shared = HtmlSystemShared(database, generator)
534
535 class HtmlInterfacesSystem(HtmlSystem):
536
537 def __init__(self, templates, database, emitters, output_dir, generator):
538 super(HtmlInterfacesSystem, self).__init__(
539 templates, database, emitters, output_dir, generator)
540 self._dart_interface_file_paths = []
541
542 def InterfaceGenerator(self,
543 interface,
544 common_prefix,
545 super_interface_name,
546 source_filter):
547 """."""
548 interface_name = interface.id
549 dart_interface_file_path = self._FilePathForDartInterface(interface_name)
550
551 self._dart_interface_file_paths.append(dart_interface_file_path)
552
553 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path)
554
555 template_file = 'interface_%s.darttemplate' % interface_name
556 template = self._templates.TryLoad(template_file)
557 if not template:
558 template = self._templates.Load('interface.darttemplate')
559
560 return HtmlDartInterfaceGenerator(
561 interface, dart_interface_code,
562 template,
563 common_prefix, super_interface_name,
564 source_filter, self, self._shared)
565
566 def ProcessCallback(self, interface, info):
567 """Generates a typedef for the callback interface."""
568 interface_name = interface.id
569 file_path = self._FilePathForDartInterface(interface_name)
570 self._ProcessCallback(interface, info, file_path)
571
572 def GenerateLibraries(self, lib_dir):
573 pass
574
575
576 def _FilePathForDartInterface(self, interface_name):
577 """Returns the file path of the Dart interface definition."""
578 # TODO(jmesserly): is this the right path
579 return os.path.join(self._output_dir, 'html', 'interface',
580 '%s.dart' % interface_name)
581
582 # ------------------------------------------------------------------------------
583
584 # TODO(jmesserly): inheritance is probably not the right way to factor this long
585 # term, but it makes merging better for now.
586 class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
587 """Generates Dart Interface definition for one DOM IDL interface."""
588
589 def __init__(self, interface, emitter, template,
590 common_prefix, super_interface, source_filter, system, shared):
591 super(HtmlDartInterfaceGenerator, self).__init__(interface,
592 emitter, template, common_prefix, super_interface, source_filter)
593 self._system = system
594 self._shared = shared
595
596 def StartInterface(self):
597 typename = self._interface.id
598
599 extends = []
600 suppressed_extends = []
601
602 for parent in self._interface.parents:
603 # TODO(vsm): Remove source_filter.
604 if MatchSourceFilter(self._source_filter, parent):
605 # Parent is a DOM type.
606 extends.append(DartType(parent.type.id))
607 elif '<' in parent.type.id:
608 # Parent is a Dart collection type.
609 # TODO(vsm): Make this check more robust.
610 extends.append(DartType(parent.type.id))
611 else:
612 suppressed_extends.append('%s.%s' %
613 (self._common_prefix, DartType(parent.type.id)))
614
615 comment = ' extends'
616 extends_str = ''
617 if extends:
618 extends_str += ' extends ' + ', '.join(extends)
619 comment = ','
620 if suppressed_extends:
621 extends_str += ' /*%s %s */' % (comment, ', '.join(suppressed_extends))
622
623 factory_provider = None
624 constructor_info = AnalyzeConstructor(self._interface)
625 if constructor_info:
626 factory_provider = '_' + typename + 'FactoryProvider';
627
628 if typename in interface_factories:
629 factory_provider = interface_factories[typename]
630
631 if factory_provider:
632 extends_str += ' default ' + factory_provider
633
634 # TODO(vsm): Add appropriate package / namespace syntax.
635 (self._members_emitter,
636 self._top_level_emitter) = self._emitter.Emit(
637 self._template + '$!TOP_LEVEL',
638 ID=typename,
639 EXTENDS=extends_str)
640
641 if constructor_info:
642 self._members_emitter.Emit(
643 '\n'
644 ' $CTOR($PARAMS);\n',
645 CTOR=typename,
646 PARAMS=constructor_info.ParametersInterfaceDeclaration());
647
648 element_type = MaybeTypedArrayElementType(self._interface)
649 if element_type:
650 self._members_emitter.Emit(
651 '\n'
652 ' $CTOR(int length);\n'
653 '\n'
654 ' $CTOR.fromList(List<$TYPE> list);\n'
655 '\n'
656 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n',
657 CTOR=self._interface.id,
658 TYPE=DartType(element_type))
659
660 emit_events, events = self._shared.GetEventAttributes(self._interface)
661 if not emit_events:
662 return
663 elif events:
664 self.AddEventAttributes(events)
665 else:
666 self._EmitEventGetter(self._shared.GetParentEventsClass(self._interface))
667
668 def AddAttribute(self, getter, setter):
669 html_getter_name = self._shared.RenameInHtmlLibrary(
670 self._interface, DartDomNameOfAttribute(getter), 'get:')
671 html_setter_name = self._shared.RenameInHtmlLibrary(
672 self._interface, DartDomNameOfAttribute(getter), 'set:')
673
674 if not html_getter_name or self._shared.IsPrivate(html_getter_name):
675 getter = None
676 if not html_setter_name or self._shared.IsPrivate(html_setter_name):
677 setter = None
678 if not getter and not setter:
679 return
680
681 # We don't yet handle inconsistent renames of the getter and setter yet.
682 if html_getter_name and html_setter_name:
683 assert html_getter_name == html_setter_name
684 if (getter and setter and
685 DartType(getter.type.id) == DartType(setter.type.id)):
686 self._members_emitter.Emit('\n $TYPE $NAME;\n',
687 NAME=html_getter_name,
688 TYPE=DartType(getter.type.id));
689 return
690 if getter and not setter:
691 self._members_emitter.Emit('\n final $TYPE $NAME;\n',
692 NAME=html_getter_name,
693 TYPE=DartType(getter.type.id));
694 return
695 raise Exception('Unexpected getter/setter combination %s %s' %
696 (getter, setter))
697
698 def AddOperation(self, info):
699 """
700 Arguments:
701 operations - contains the overloads, one or more operations with the same
702 name.
703 """
704 html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
705 if html_name and not self._shared.IsPrivate(html_name):
706 self._members_emitter.Emit('\n'
707 ' $TYPE $NAME($PARAMS);\n',
708 TYPE=info.type_name,
709 NAME=html_name,
710 PARAMS=info.ParametersInterfaceDeclaration())
711
712 def FinishInterface(self):
713 pass
714
715 def AddConstant(self, constant):
716 self._EmitConstant(self._members_emitter, constant)
717
718 def AddEventAttributes(self, event_attrs):
719 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
720 self._shared._event_classes.add(self._interface.id)
721 events_interface = self._interface.id + 'Events'
722 self._EmitEventGetter(events_interface)
723
724 events_members = self._emitter.Emit(
725 '\ninterface $INTERFACE extends $PARENTS {\n$!MEMBERS}\n',
726 INTERFACE=events_interface,
727 PARENTS=', '.join(
728 self._shared.GetParentsEventsClasses(self._interface)))
729
730 for event_name in event_attrs:
731 if event_name in _html_event_names:
732 events_members.Emit('\n EventListenerList get $NAME();\n',
733 NAME=_html_event_names[event_name])
734 else:
735 raise Exception('No known html even name for event: ' + event_name)
736
737 def _EmitEventGetter(self, events_interface):
738 self._members_emitter.Emit('\n $TYPE get on();\n',
739 TYPE=events_interface)
740
741 # ------------------------------------------------------------------------------
742
743 # TODO(jmesserly): inheritance is probably not the right way to factor this long
744 # term, but it makes merging better for now.
745 class HtmlFrogClassGenerator(FrogInterfaceGenerator):
746 """Generates a Frog class for the dart:html library from a DOM IDL
747 interface.
748 """
749
750 def __init__(self, system, interface, template, super_interface, dart_code,
751 shared):
752 super(HtmlFrogClassGenerator, self).__init__(
753 system, interface, template, super_interface, dart_code)
754 self._shared = shared
755
756 def _ImplClassName(self, type_name):
757 return self._shared._ImplClassName(type_name)
758
759 def StartInterface(self):
760 interface = self._interface
761 interface_name = interface.id
762
763 self._class_name = self._ImplClassName(interface_name)
764
765 base = None
766 if interface.parents:
767 supertype = interface.parents[0].type.id
768 if IsDartCollectionType(supertype):
769 # List methods are injected in AddIndexer.
770 pass
771 else:
772 base = self._ImplClassName(supertype)
773
774 native_spec = MakeNativeSpec(interface.javascript_binding_name)
775
776 extends = ' extends ' + base if base else ''
777
778 # TODO: Include all implemented interfaces, including other Lists.
779 implements = [interface_name]
780 element_type = MaybeTypedArrayElementType(self._interface)
781 if element_type:
782 implements.append('List<%s>' % DartType(element_type))
783
784 self._members_emitter = self._dart_code.Emit(
785 self._template,
786 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
787 #$!MEMBERS
788 #}
789 CLASSNAME=self._class_name,
790 EXTENDS=extends,
791 IMPLEMENTS=' implements ' + ', '.join(implements),
792 NATIVESPEC=' native "' + native_spec + '"')
793
794 if element_type:
795 self.AddTypedArrayConstructors(element_type)
796
797 # Emit a factory provider class for the constructor.
798 constructor_info = AnalyzeConstructor(interface)
799 if constructor_info:
800 self._EmitFactoryProvider(interface_name, constructor_info)
801
802 emit_events, events = self._shared.GetEventAttributes(self._interface)
803 if not emit_events:
804 return
805 elif events:
806 self.AddEventAttributes(events)
807 else:
808 parent_events_class = self._shared.GetParentEventsClass(self._interface)
809 self._EmitEventGetter('_' + parent_events_class + 'Impl')
810
811 def _EmitFactoryProvider(self, interface_name, constructor_info):
812 template_file = 'factoryprovider_%s.darttemplate' % interface_name
813 template = self._system._templates.TryLoad(template_file)
814 if not template:
815 template = self._system._templates.Load('factoryprovider.darttemplate')
816
817 factory_provider = '_' + interface_name + 'FactoryProvider'
818 emitter = self._system._ImplFileEmitter(factory_provider)
819 emitter.Emit(
820 template,
821 FACTORYPROVIDER=factory_provider,
822 CONSTRUCTOR=interface_name,
823 PARAMETERS=constructor_info.ParametersImplementationDeclaration(),
824 NAMED_CONSTRUCTOR=constructor_info.name or interface_name,
825 ARGUMENTS=constructor_info.ParametersAsArgumentList())
826
827 def AddIndexer(self, element_type):
828 """Adds all the methods required to complete implementation of List."""
829 # We would like to simply inherit the implementation of everything except
830 # get length(), [], and maybe []=. It is possible to extend from a base
831 # array implementation class only when there is no other implementation
832 # inheritance. There might be no implementation inheritance other than
833 # DOMBaseWrapper for many classes, but there might be some where the
834 # array-ness is introduced by a non-root interface:
835 #
836 # interface Y extends X, List<T> ...
837 #
838 # In the non-root case we have to choose between:
839 #
840 # class YImpl extends XImpl { add List<T> methods; }
841 #
842 # and
843 #
844 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
845 #
846 self._members_emitter.Emit(
847 '\n'
848 ' $TYPE operator[](int index) native "return this[index];";\n',
849 TYPE=self._NarrowOutputType(element_type))
850
851 if 'CustomIndexedSetter' in self._interface.ext_attrs:
852 self._members_emitter.Emit(
853 '\n'
854 ' void operator[]=(int index, $TYPE value) native "this[index] = valu e";\n',
855 TYPE=self._NarrowInputType(element_type))
856 else:
857 # The HTML library implementation of NodeList has a custom indexed setter
858 # implementation that uses the parent node the NodeList is associated
859 # with if one is available.
860 if self._interface.id != 'NodeList':
861 self._members_emitter.Emit(
862 '\n'
863 ' void operator[]=(int index, $TYPE value) {\n'
864 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
865 ' }\n',
866 TYPE=self._NarrowInputType(element_type))
867
868 # TODO(sra): Use separate mixins for mutable implementations of List<T>.
869 # TODO(sra): Use separate mixins for typed array implementations of List<T>.
870 if self._interface.id != 'NodeList':
871 template_file = 'immutable_list_mixin.darttemplate'
872 template = self._system._templates.Load(template_file)
873 self._members_emitter.Emit(template, E=DartType(element_type))
874
875 def AddAttribute(self, getter, setter):
876
877 html_getter_name = self._shared.RenameInHtmlLibrary(
878 self._interface, DartDomNameOfAttribute(getter), 'get:')
879 html_setter_name = self._shared.RenameInHtmlLibrary(
880 self._interface, DartDomNameOfAttribute(getter), 'set:')
881
882 if not html_getter_name:
883 getter = None
884 if not html_setter_name:
885 setter = None
886
887 if not getter and not setter:
888 return
889
890 if ((getter and (html_getter_name != getter.id or
891 self._shared.MaybeReturnDocument(getter.type.id))) or
892 (setter and (html_setter_name != setter.id or
893 self._shared.MaybeReturnDocument(setter.type.id))) or
894 self._interface.id == 'Document'):
895 if getter:
896 self._AddRenamingGetter(getter, html_getter_name)
897 if setter:
898 self._AddRenamingSetter(setter, html_setter_name)
899 return
900
901 # If the (getter, setter) pair is shadowing, we can't generate a shadowing
902 # field (Issue 1633).
903 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter)
904 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter)
905 if super_getter or super_setter:
906 if getter and not setter and super_getter and not super_setter:
907 if DartType(getter.type.id) == DartType(super_getter.type.id):
908 # Compatible getter, use the superclass property. This works because
909 # JavaScript will do its own dynamic dispatch.
910 output_type = getter and self._NarrowOutputType(getter.type.id)
911 self._members_emitter.Emit(
912 '\n'
913 ' // Use implementation from $SUPER.\n'
914 ' // final $TYPE $NAME;\n',
915 SUPER=super_getter_interface.id,
916 NAME=DartDomNameOfAttribute(getter),
917 TYPE=output_type)
918 return
919
920 self._members_emitter.Emit('\n // Shadowing definition.')
921 self._AddAttributeUsingProperties(getter, setter)
922 return
923
924 output_type = getter and self._NarrowOutputType(getter.type.id)
925 input_type = setter and self._NarrowInputType(setter.type.id)
926 if getter and setter and input_type == output_type:
927 self._members_emitter.Emit(
928 '\n $TYPE $NAME;\n',
929 NAME=DartDomNameOfAttribute(getter),
930 TYPE=output_type)
931 return
932 if getter and not setter:
933 self._members_emitter.Emit(
934 '\n final $TYPE $NAME;\n',
935 NAME=DartDomNameOfAttribute(getter),
936 TYPE=output_type)
937 return
938 self._AddAttributeUsingProperties(getter, setter)
939
940 def _AddAttributeUsingProperties(self, getter, setter):
941 if getter:
942 self._AddGetter(getter)
943 if setter:
944 self._AddSetter(setter)
945
946 def _AddGetter(self, attr):
947 self._AddRenamingGetter(attr, DartDomNameOfAttribute(attr))
948
949 def _AddSetter(self, attr):
950 self._AddRenamingSetter(attr, DartDomNameOfAttribute(attr))
951
952 def _AddRenamingGetter(self, attr, html_name):
953 return_type = self._NarrowOutputType(attr.type.id)
954 if self._shared.MaybeReturnDocument(attr.type.id):
955 self._members_emitter.Emit(
956 '\n $TYPE get $(HTML_NAME)() => '
957 '_FixHtmlDocumentReference(_$(HTML_NAME));\n',
958 HTML_NAME=html_name,
959 TYPE=return_type)
960 html_name = '_' + html_name
961 # For correctness this needs to be the return type of the native helper
962 # method due to the fact that the real HTMLDocument object is not typed
963 # as a document. TODO(jacobr): we could simplify this.
964 return_type = '_EventTargetImpl'
965
966 self._members_emitter.Emit(
967 '\n $TYPE get $(HTML_NAME)() native "return $(THIS).$NAME;";\n',
968 HTML_NAME=html_name,
969 NAME=attr.id,
970 TYPE=return_type,
971 THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
972
973 def _AddRenamingSetter(self, attr, html_name):
974 self._members_emitter.Emit(
975 '\n void set $HTML_NAME($TYPE value)'
976 ' native "$(THIS).$NAME = value;";\n',
977 HTML_NAME=html_name,
978 NAME=attr.id,
979 TYPE=self._NarrowInputType(attr.type.id),
980 THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
981
982 def AddOperation(self, info):
983 """
984 Arguments:
985 info: An OperationInfo object.
986 """
987 html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
988 if not html_name:
989 return
990
991 maybe_return_document = self._shared.MaybeReturnDocument(info.type_name)
992
993 # Do we need a native body?
994 if (self._interface.id == 'Document' or # Need alternate 'this'
995 html_name != info.name or # renamed operation
996 maybe_return_document): # need to wrap value
997 # For example: use window.document instead of his.parentNode.
998 return_type = self._NarrowOutputType(info.type_name)
999
1000 operation_emitter = self._members_emitter.Emit('$!SCOPE',
1001 THIS=('this.parentNode' if self._interface.id == 'Document'
1002 else 'this'),
1003 TYPE=return_type,
1004 HTML_NAME=html_name,
1005 NAME=info.name,
1006 RETURN='' if return_type == 'void' else 'return ',
1007 PARAMNAMES=info.ParametersAsArgumentList(),
1008 PARAMS=info.ParametersImplementationDeclaration(
1009 lambda type_name: self._NarrowInputType(type_name)))
1010
1011 if maybe_return_document:
1012 assert len(info.overloads) == 1
1013 operation_emitter.Emit(
1014 '\n'
1015 ' $TYPE $(HTML_NAME)($PARAMS) => '
1016 '_FixHtmlDocumentReference(_$(HTML_NAME)($PARAMNAMES));\n'
1017 '\n'
1018 ' _EventTargetImpl _$(HTML_NAME)($PARAMS)'
1019 ' native "return $(THIS).$NAME($PARAMNAMES);";\n')
1020 else:
1021 operation_emitter.Emit(
1022 '\n'
1023 ' $TYPE $(HTML_NAME)($PARAMS)'
1024 ' native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n')
1025 else:
1026 self._members_emitter.Emit(
1027 '\n'
1028 ' $TYPE $NAME($PARAMS) native;\n',
1029 TYPE=self._NarrowOutputType(info.type_name),
1030 NAME=info.name,
1031 PARAMS=info.ParametersImplementationDeclaration(
1032 lambda type_name: self._NarrowInputType(type_name)))
1033
1034 def AddEventAttributes(self, event_attrs):
1035 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
1036 events_class = '_' + self._interface.id + 'EventsImpl'
1037 events_interface = self._interface.id + 'Events'
1038 self._EmitEventGetter(events_class)
1039
1040 self._shared._event_classes.add(self._interface.id)
1041
1042 parent_event_class = self._shared.GetParentEventsClass(self._interface)
1043
1044 # TODO(jacobr): specify the type of _ptr as EventTarget
1045 events_members = self._dart_code.Emit(
1046 '\n'
1047 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
1048 ' $CLASSNAME(_ptr) : super(_ptr);\n'
1049 '$!MEMBERS}\n',
1050 CLASSNAME=events_class,
1051 INTERFACE=events_interface,
1052 SUPER='_' + parent_event_class + 'Impl')
1053
1054 for event_name in event_attrs:
1055 if event_name in _html_event_names:
1056 events_members.Emit(
1057 "\n"
1058 " EventListenerList get $NAME() => _get('$RAWNAME');\n",
1059 RAWNAME=event_name,
1060 NAME=_html_event_names[event_name])
1061 else:
1062 raise Exception('No known html even name for event: ' + event_name)
1063
1064 def _EmitEventGetter(self, events_class):
1065 self._members_emitter.Emit(
1066 '\n $TYPE get on() =>\n new $TYPE($EVENTTARGET);\n',
1067 TYPE=events_class,
1068 EVENTTARGET='_jsDocument' if self._interface.id == 'Document'
1069 else 'this')
1070
1071 # ------------------------------------------------------------------------------
1072
1073 class HtmlFrogSystem(HtmlSystem):
1074
1075 def __init__(self, templates, database, emitters, output_dir, generator):
1076 super(HtmlFrogSystem, self).__init__(
1077 templates, database, emitters, output_dir, generator)
1078 self._dart_frog_file_paths = []
1079
1080
1081 def InterfaceGenerator(self,
1082 interface,
1083 common_prefix,
1084 super_interface_name,
1085 source_filter):
1086 """."""
1087 template_file = 'impl_%s.darttemplate' % interface.id
1088 template = self._templates.TryLoad(template_file)
1089 if not template:
1090 template = self._templates.Load('frog_impl.darttemplate')
1091
1092 dart_code = self._ImplFileEmitter(interface.id)
1093 return HtmlFrogClassGenerator(self, interface, template,
1094 super_interface_name, dart_code, self._shared)
1095
1096 def GenerateLibraries(self, lib_dir):
1097 self._GenerateLibFile(
1098 'html_frog.darttemplate',
1099 os.path.join(lib_dir, 'html_frog.dart'),
1100 (self._interface_system._dart_interface_file_paths +
1101 self._interface_system._dart_callback_file_paths +
1102 self._dart_frog_file_paths))
1103
1104 def Finish(self):
1105 pass
1106
1107 def _ImplFileEmitter(self, name):
1108 """Returns the file emitter of the Frog implementation file."""
1109 # TODO(jmesserly): is this the right path
1110 path = os.path.join(self._output_dir, 'html', 'frog', '%s.dart' % name)
1111 self._dart_frog_file_paths.append(path)
1112 return self._emitters.FileEmitter(path)
1113
1114 # -----------------------------------------------------------------------------
1115
1116 class HtmlDartiumSystem(HtmlSystem):
1117
1118 def __init__(self, templates, database, emitters, output_dir, generator):
1119 """Prepared for generating wrapping implementation.
1120
1121 - Creates emitter for Dart code.
1122 """
1123 super(HtmlDartiumSystem, self).__init__(
1124 templates, database, emitters, output_dir, generator)
1125 self._shared = HtmlSystemShared(database, generator)
1126 self._dart_dartium_file_paths = []
1127 self._wrap_cases = []
1128
1129 def InterfaceGenerator(self,
1130 interface,
1131 common_prefix,
1132 super_interface_name,
1133 source_filter):
1134 """."""
1135 template_file = 'impl_%s.darttemplate' % interface.id
1136 template = self._templates.TryLoad(template_file)
1137 # TODO(jacobr): change this name as it is confusing.
1138 if not template:
1139 template = self._templates.Load('frog_impl.darttemplate')
1140
1141 dart_code = self._ImplFileEmitter(interface.id)
1142 return HtmlDartiumInterfaceGenerator(self, interface, template,
1143 super_interface_name, dart_code, self._BaseDefines(interface),
1144 self._shared)
1145
1146 def _ImplFileEmitter(self, name):
1147 """Returns the file emitter of the Dartium implementation file."""
1148 path = os.path.join(self._output_dir, 'html', 'dartium', '%s.dart' % name)
1149 self._dart_dartium_file_paths.append(path)
1150 return self._emitters.FileEmitter(path);
1151
1152 def ProcessCallback(self, interface, info):
1153 pass
1154
1155 def GenerateLibraries(self, lib_dir):
1156 # Library generated for implementation.
1157 self._GenerateLibFile(
1158 'html_dartium.darttemplate',
1159 os.path.join(lib_dir, 'html_dartium.dart'),
1160 (self._interface_system._dart_interface_file_paths +
1161 self._interface_system._dart_callback_file_paths +
1162 self._dart_dartium_file_paths
1163 ),
1164 WRAPCASES='\n'.join(self._wrap_cases))
1165
1166 def Finish(self):
1167 pass
1168
1169 # ------------------------------------------------------------------------------
1170
1171 # TODO(jacobr): there is far too much duplicated code between these bindings
1172 # and the Frog bindings. A larger scale refactoring needs to be performed to
1173 # reduce the duplicated logic.
1174 class HtmlDartiumInterfaceGenerator(object):
1175 """Generates a wrapper based implementation fo the HTML library that works
1176 on Dartium. This is not intended to be the final solution for implementing
1177 dart:html on Dartium. Eventually we should generate direct wrapperless
1178 dart:html bindings that work on dartium."""
1179
1180 def __init__(self, system, interface, template, super_interface, dart_code,
1181 base_members, shared):
1182 """Generates Dart wrapper code for the given interface.
1183
1184 Args:
1185 system: system that is executing this generator.
1186 template: template that output is generated into.
1187 interface: an IDLInterface instance. It is assumed that all types have
1188 been converted to Dart types (e.g. int, String), unless they are in
1189 the same package as the interface.
1190 super_interface: A string or None, the name of the common interface that
1191 this interface implements, if any.
1192 dart_code: an Emitter for the file containing the Dart implementation
1193 class.
1194 base_members: a set of names of members defined in a base class. This is
1195 used to avoid static member 'overriding' in the generated Dart code.
1196 shared: functionaly shared across all Html generators.
1197 """
1198 self._system = system
1199 self._interface = interface
1200 self._super_interface = super_interface
1201 self._dart_code = dart_code
1202 self._base_members = base_members
1203 self._current_secondary_parent = None
1204 self._shared = shared
1205 self._template = template
1206
1207 def DomObjectName(self):
1208 return '_documentPtr' if self._interface.id == 'Document' else '_ptr'
1209
1210 # TODO(jacobr): these 3 methods are duplicated.
1211 def _NarrowToImplementationType(self, type_name):
1212 # TODO(sra): Move into the 'system' and cache the result.
1213 if type_name == 'EventListener':
1214 # Callbacks are typedef functions so don't have a class.
1215 return type_name
1216 if self._system._database.HasInterface(type_name):
1217 interface = self._system._database.GetInterface(type_name)
1218 if RecognizeCallback(interface):
1219 # Callbacks are typedef functions so don't have a class.
1220 return type_name
1221 else:
1222 return self._ImplClassName(type_name)
1223 return type_name
1224
1225 def _NarrowInputType(self, type_name):
1226 return self._NarrowToImplementationType(type_name)
1227
1228 def _NarrowOutputType(self, type_name):
1229 return self._NarrowToImplementationType(type_name)
1230
1231 def StartInterface(self):
1232
1233 interface = self._interface
1234 interface_name = interface.id
1235 self._class_name = self._ImplClassName(interface_name)
1236
1237 base = None
1238 if interface.parents:
1239 supertype = interface.parents[0].type.id
1240 if not IsDartListType(supertype):
1241 base = self._ImplClassName(supertype)
1242 if IsDartCollectionType(supertype):
1243 # List methods are injected in AddIndexer.
1244 pass
1245 else:
1246 base = self._ImplClassName(supertype)
1247
1248 # TODO(jacobr): this is fragile. There isn't a guarantee that dart:dom
1249 # will continue to exactly match the IDL names.
1250 dom_name = interface.javascript_binding_name
1251 # We hard code the cases for these classes
1252 if dom_name != 'HTMLHtmlElement' and dom_name != 'Document':
1253 self._system._wrap_cases.append(
1254 ' case "%s": return new %s._wrap(domObject);' %
1255 (dom_name, self._class_name))
1256
1257 extends = ' extends ' + base if base else ' extends _DOMTypeBase'
1258
1259 # TODO: Include all implemented interfaces, including other Lists.
1260 implements = [interface_name]
1261 element_type = MaybeTypedArrayElementType(self._interface)
1262 if element_type:
1263 implements.append('List<' + DartType(element_type) + '>')
1264 implements_str = ', '.join(implements)
1265
1266 (self._members_emitter,
1267 self._top_level_emitter) = self._dart_code.Emit(
1268 self._template + '$!TOP_LEVEL',
1269 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
1270 #$!MEMBERS
1271 #}
1272 NATIVESPEC='', # hack to make reusing the same templates work.
1273 CLASSNAME=self._class_name,
1274 EXTENDS=extends,
1275 IMPLEMENTS=' implements ' + implements_str)
1276
1277 # Document requires a custom wrapper.
1278 if dom_name != 'Document':
1279 self._members_emitter.Emit(
1280 ' $(CLASSNAME)._wrap(ptr) : super._wrap(ptr);\n',
1281 CLASSNAME=self._class_name)
1282
1283 # Emit a factory provider class for the constructor.
1284 constructor_info = AnalyzeConstructor(interface)
1285 if constructor_info:
1286 self._EmitFactoryProvider(interface_name, constructor_info)
1287
1288 emit_events, events = self._shared.GetEventAttributes(self._interface)
1289 if not emit_events:
1290 return
1291 elif events:
1292 self.AddEventAttributes(events)
1293 else:
1294 parent_events_class = self._shared.GetParentEventsClass(self._interface)
1295 self._EmitEventGetter('_' + parent_events_class + 'Impl')
1296
1297 def _EmitFactoryProvider(self, interface_name, constructor_info):
1298 template_file = 'factoryprovider_%s.darttemplate' % interface_name
1299 template = self._system._templates.TryLoad(template_file)
1300 if not template:
1301 template = self._system._templates.Load('factoryprovider.darttemplate')
1302
1303 factory_provider = '_' + interface_name + 'FactoryProvider'
1304 emitter = self._system._ImplFileEmitter(factory_provider)
1305 emitter.Emit(
1306 template,
1307 FACTORYPROVIDER=factory_provider,
1308 CONSTRUCTOR=interface_name,
1309 PARAMETERS=constructor_info.ParametersImplementationDeclaration(),
1310 NAMED_CONSTRUCTOR=constructor_info.name or interface_name,
1311 ARGUMENTS=self._UnwrappedParameters(constructor_info,
1312 len(constructor_info.arg_infos)))
1313
1314 def _UnwrappedParameters(self, operation_info, length):
1315 """Returns string for an argument list that unwraps first |length|
1316 parameters."""
1317 def UnwrapArgInfo(arg_info):
1318 (name, type, value) = arg_info
1319 # TODO(sra): Type dependent unwrapping.
1320 return '_unwrap(%s)' % name
1321
1322 return ', '.join(map(UnwrapArgInfo, operation_info.arg_infos[:length]))
1323
1324 def _BaseClassName(self, interface):
1325 if not interface.parents:
1326 return '_DOMTypeBase'
1327
1328 supertype = DartType(interface.parents[0].type.id)
1329
1330 if IsDartListType(supertype) or IsDartCollectionType(supertype):
1331 return 'DOMWrapperBase'
1332
1333 if supertype == 'EventTarget':
1334 # Most implementors of EventTarget specify the EventListener operations
1335 # again. If the operations are not specified, try to inherit from the
1336 # EventTarget implementation.
1337 #
1338 # Applies to MessagePort.
1339 if not [op for op in interface.operations if op.id == 'addEventListener']:
1340 return self._ImplClassName(supertype)
1341 return 'DOMWrapperBase'
1342
1343 return self._ImplClassName(supertype)
1344
1345 def _ImplClassName(self, type_name):
1346 return self._shared._ImplClassName(type_name)
1347
1348 def FinishInterface(self):
1349 """."""
1350 pass
1351
1352 def AddConstant(self, constant):
1353 # Constants are already defined on the interface.
1354 pass
1355
1356 def _MethodName(self, prefix, name):
1357 method_name = prefix + name
1358 if name in self._base_members: # Avoid illegal Dart 'static override'.
1359 method_name = method_name + '_' + self._interface.id
1360 return method_name
1361
1362 def AddAttribute(self, getter, setter):
1363 dom_name = DartDomNameOfAttribute(getter or setter)
1364 html_getter_name = self._shared.RenameInHtmlLibrary(
1365 self._interface, dom_name, 'get:')
1366 html_setter_name = self._shared.RenameInHtmlLibrary(
1367 self._interface, dom_name, 'set:')
1368
1369 if getter and html_getter_name:
1370 self._AddGetter(getter, html_getter_name)
1371 if setter and html_setter_name:
1372 self._AddSetter(setter, html_setter_name)
1373
1374 def _AddGetter(self, attr, html_name):
1375 if self._shared.MaybeReturnDocument(attr.type.id):
1376 self._members_emitter.Emit(
1377 '\n'
1378 ' $TYPE get $(HTML_NAME)() => '
1379 '_FixHtmlDocumentReference(_wrap($(THIS).$DOM_NAME));\n',
1380 HTML_NAME=html_name,
1381 DOM_NAME=DartDomNameOfAttribute(attr),
1382 TYPE=DartType(attr.type.id),
1383 THIS=self.DomObjectName())
1384 else:
1385 self._members_emitter.Emit(
1386 '\n'
1387 ' $TYPE get $(HTML_NAME)() => _wrap($(THIS).$DOM_NAME);\n',
1388 HTML_NAME=html_name,
1389 DOM_NAME=DartDomNameOfAttribute(attr),
1390 TYPE=DartType(attr.type.id),
1391 THIS=self.DomObjectName())
1392
1393 def _AddSetter(self, attr, html_name):
1394 self._members_emitter.Emit(
1395 '\n'
1396 ' void set $(HTML_NAME)($TYPE value) { '
1397 '$(THIS).$DOM_NAME = _unwrap(value); }\n',
1398 HTML_NAME=html_name,
1399 DOM_NAME=DartDomNameOfAttribute(attr),
1400 TYPE=DartType(attr.type.id),
1401 THIS=self.DomObjectName())
1402
1403 def AddSecondaryAttribute(self, interface, getter, setter):
1404 self._SecondaryContext(interface)
1405 self.AddAttribute(getter, setter)
1406
1407 def AddSecondaryOperation(self, interface, info):
1408 self._SecondaryContext(interface)
1409 self.AddOperation(info)
1410
1411 def AddEventAttributes(self, event_attrs):
1412 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
1413 events_class = '_' + self._interface.id + 'EventsImpl'
1414 events_interface = self._interface.id + 'Events'
1415 self._EmitEventGetter(events_class)
1416
1417 self._shared._event_classes.add(self._interface.id)
1418
1419 parent_event_class = self._shared.GetParentEventsClass(self._interface)
1420
1421 # TODO(jacobr): specify the type of _ptr as EventTarget
1422 events_members = self._dart_code.Emit(
1423 '\n'
1424 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
1425 ' $CLASSNAME(_ptr) : super(_ptr);\n'
1426 '$!MEMBERS}\n',
1427 CLASSNAME=events_class,
1428 INTERFACE=events_interface,
1429 SUPER='_' + parent_event_class + 'Impl')
1430
1431 for event_name in event_attrs:
1432 if event_name in _html_event_names:
1433 events_members.Emit(
1434 "\n"
1435 " EventListenerList get $NAME() => _get('$RAWNAME');\n",
1436 RAWNAME=event_name,
1437 NAME=_html_event_names[event_name])
1438 else:
1439 raise Exception('No known html even name for event: ' + event_name)
1440
1441 def _EmitEventGetter(self, events_class):
1442 self._members_emitter.Emit(
1443 '\n'
1444 ' $TYPE get on() {\n'
1445 ' if (_on == null) _on = new $TYPE($EVENTTARGET);\n'
1446 ' return _on;\n'
1447 ' }\n',
1448 TYPE=events_class,
1449 EVENTTARGET='_wrappedDocumentPtr' if self._interface.id == 'Document'
1450 else 'this')
1451
1452 def _SecondaryContext(self, interface):
1453 if interface is not self._current_secondary_parent:
1454 self._current_secondary_parent = interface
1455 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id)
1456
1457 # TODO(jacobr): change this to more directly match the frog version.
1458 def AddIndexer(self, element_type):
1459 """Adds all the methods required to complete implementation of List."""
1460 # We would like to simply inherit the implementation of everything except
1461 # get length(), [], and maybe []=. It is possible to extend from a base
1462 # array implementation class only when there is no other implementation
1463 # inheritance. There might be no implementation inheritance other than
1464 # DOMBaseWrapper for many classes, but there might be some where the
1465 # array-ness is introduced by a non-root interface:
1466 #
1467 # interface Y extends X, List<T> ...
1468 #
1469 # In the non-root case we have to choose between:
1470 #
1471 # class YImpl extends XImpl { add List<T> methods; }
1472 #
1473 # and
1474 #
1475 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
1476 #
1477 if self._HasNativeIndexGetter(self._interface):
1478 self._EmitNativeIndexGetter(self._interface, element_type)
1479 else:
1480 self._members_emitter.Emit(
1481 '\n'
1482 ' $TYPE operator[](int index) => _wrap($(THIS)[index]);\n'
1483 '\n',
1484 THIS=self.DomObjectName(),
1485 TYPE=DartType(element_type))
1486
1487 if self._HasNativeIndexSetter(self._interface):
1488 self._EmitNativeIndexSetter(self._interface, element_type)
1489 else:
1490 # The HTML library implementation of NodeList has a custom indexed setter
1491 # implementation that uses the parent node the NodeList is associated
1492 # with if one is available.
1493 if self._interface.id != 'NodeList':
1494 self._members_emitter.Emit(
1495 '\n'
1496 ' void operator[]=(int index, $TYPE value) {\n'
1497 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
1498 ' }\n',
1499 TYPE=DartType(element_type))
1500
1501 # The list interface for this class is manually generated.
1502 if self._interface.id == 'NodeList':
1503 return
1504
1505 self._members_emitter.Emit(
1506 '\n'
1507 ' void add($TYPE value) {\n'
1508 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1509 ' }\n'
1510 '\n'
1511 ' void addLast($TYPE value) {\n'
1512 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1513 ' }\n'
1514 '\n'
1515 ' void addAll(Collection<$TYPE> collection) {\n'
1516 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1517 ' }\n'
1518 '\n'
1519 ' void sort(int compare($TYPE a, $TYPE b)) {\n'
1520 ' throw new UnsupportedOperationException("Cannot sort immutable List .");\n'
1521 ' }\n'
1522 '\n'
1523 ' void copyFrom(List<Object> src, int srcStart, '
1524 'int dstStart, int count) {\n'
1525 ' throw new UnsupportedOperationException("This object is immutable." );\n'
1526 ' }\n'
1527 '\n'
1528 ' int indexOf($TYPE element, [int start = 0]) {\n'
1529 ' return _Lists.indexOf(this, element, start, this.length);\n'
1530 ' }\n'
1531 '\n'
1532 ' int lastIndexOf($TYPE element, [int start = null]) {\n'
1533 ' if (start === null) start = length - 1;\n'
1534 ' return _Lists.lastIndexOf(this, element, start);\n'
1535 ' }\n'
1536 '\n'
1537 ' int clear() {\n'
1538 ' throw new UnsupportedOperationException("Cannot clear immutable Lis t.");\n'
1539 ' }\n'
1540 '\n'
1541 ' $TYPE removeLast() {\n'
1542 ' throw new UnsupportedOperationException("Cannot removeLast on immut able List.");\n'
1543 ' }\n'
1544 '\n'
1545 ' $TYPE last() {\n'
1546 ' return this[length - 1];\n'
1547 ' }\n'
1548 '\n'
1549 ' void forEach(void f($TYPE element)) {\n'
1550 ' _Collections.forEach(this, f);\n'
1551 ' }\n'
1552 '\n'
1553 ' Collection map(f($TYPE element)) {\n'
1554 ' return _Collections.map(this, [], f);\n'
1555 ' }\n'
1556 '\n'
1557 ' Collection<$TYPE> filter(bool f($TYPE element)) {\n'
1558 ' return _Collections.filter(this, new List<$TYPE>(), f);\n'
1559 ' }\n'
1560 '\n'
1561 ' bool every(bool f($TYPE element)) {\n'
1562 ' return _Collections.every(this, f);\n'
1563 ' }\n'
1564 '\n'
1565 ' bool some(bool f($TYPE element)) {\n'
1566 ' return _Collections.some(this, f);\n'
1567 ' }\n'
1568 '\n'
1569 ' void setRange(int start, int length, List<$TYPE> from, [int startFrom ]) {\n'
1570 ' throw new UnsupportedOperationException("Cannot setRange on immutab le List.");\n'
1571 ' }\n'
1572 '\n'
1573 ' void removeRange(int start, int length) {\n'
1574 ' throw new UnsupportedOperationException("Cannot removeRange on immu table List.");\n'
1575 ' }\n'
1576 '\n'
1577 ' void insertRange(int start, int length, [$TYPE initialValue]) {\n'
1578 ' throw new UnsupportedOperationException("Cannot insertRange on immu table List.");\n'
1579 ' }\n'
1580 '\n'
1581 ' List<$TYPE> getRange(int start, int length) {\n'
1582 ' throw new NotImplementedException();\n'
1583 ' }\n'
1584 '\n'
1585 ' bool isEmpty() {\n'
1586 ' return length == 0;\n'
1587 ' }\n'
1588 '\n'
1589 ' Iterator<$TYPE> iterator() {\n'
1590 ' return new _FixedSizeListIterator<$TYPE>(this);\n'
1591 ' }\n',
1592 TYPE=DartType(element_type))
1593
1594 def _HasNativeIndexGetter(self, interface):
1595 return ('HasIndexGetter' in interface.ext_attrs or
1596 'HasNumericIndexGetter' in interface.ext_attrs)
1597
1598 def _EmitNativeIndexGetter(self, interface, element_type):
1599 method_name = '_index'
1600 self._members_emitter.Emit(
1601 '\n $TYPE operator[](int index) => _wrap($(THIS)[index]);\n',
1602 TYPE=DartType(element_type),
1603 THIS=self.DomObjectName(),
1604 METHOD=method_name)
1605
1606 def _HasNativeIndexSetter(self, interface):
1607 return 'HasCustomIndexSetter' in interface.ext_attrs
1608
1609 def _EmitNativeIndexSetter(self, interface, element_type):
1610 method_name = '_set_index'
1611 self._members_emitter.Emit(
1612 '\n'
1613 ' void operator[]=(int index, $TYPE value) {\n'
1614 ' return $(THIS)[index] = _unwrap(value);\n'
1615 ' }\n',
1616 THIS=self.DomObjectName(),
1617 TYPE=DartType(element_type),
1618 METHOD=method_name)
1619
1620 def AddOperation(self, info):
1621 """
1622 Arguments:
1623 info: An OperationInfo object.
1624 """
1625 html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
1626
1627 if not html_name:
1628 return
1629
1630 body = self._members_emitter.Emit(
1631 '\n'
1632 ' $TYPE $HTML_NAME($PARAMS) {\n'
1633 '$!BODY'
1634 ' }\n',
1635 TYPE=info.type_name,
1636 HTML_NAME=html_name,
1637 PARAMS=info.ParametersImplementationDeclaration())
1638
1639 # Process in order of ascending number of arguments to ensure missing
1640 # optional arguments are processed early.
1641 overloads = sorted(info.overloads,
1642 key=lambda overload: len(overload.arguments))
1643 self._native_version = 0
1644 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads)
1645 if fallthrough:
1646 body.Emit(' throw "Incorrect number or type of arguments";\n');
1647
1648 def GenerateSingleOperation(self, emitter, info, indent, operation):
1649 """Generates a call to a single operation.
1650
1651 Arguments:
1652 emitter: an Emitter for the body of a block of code.
1653 info: the compound information about the operation and its overloads.
1654 indent: an indentation string for generated code.
1655 operation: the IDLOperation to call.
1656 """
1657 argument_expressions = self._UnwrappedParameters(
1658 info,
1659 len(operation.arguments)) # Just the parameters this far.
1660
1661 if info.type_name != 'void':
1662 # We could place the logic for handling Document directly in _wrap
1663 # but we chose to place it here so that bugs in the wrapper and
1664 # wrapperless implementations are more consistent.
1665 if self._shared.MaybeReturnDocument(info.type_name):
1666 emitter.Emit('$(INDENT)return _FixHtmlDocumentReference('
1667 '_wrap($(THIS).$NAME($ARGS)));\n',
1668 INDENT=indent,
1669 THIS=self.DomObjectName(),
1670 NAME=info.name,
1671 ARGS=argument_expressions)
1672 else:
1673 emitter.Emit('$(INDENT)return _wrap($(THIS).$NAME($ARGS));\n',
1674 INDENT=indent,
1675 THIS=self.DomObjectName(),
1676 NAME=info.name,
1677 ARGS=argument_expressions)
1678 else:
1679 emitter.Emit('$(INDENT)$(THIS).$NAME($ARGS);\n'
1680 '$(INDENT)return;\n',
1681 INDENT=indent,
1682 THIS=self.DomObjectName(),
1683 NAME=info.name,
1684 ARGS=argument_expressions)
1685
1686 def GenerateDispatch(self, emitter, info, indent, position, overloads):
1687 """Generates a dispatch to one of the overloads.
1688
1689 Arguments:
1690 emitter: an Emitter for the body of a block of code.
1691 info: the compound information about the operation and its overloads.
1692 indent: an indentation string for generated code.
1693 position: the index of the parameter to dispatch on.
1694 overloads: a list of the remaining IDLOperations to dispatch.
1695
1696 Returns True if the dispatch can fall through on failure, False if the code
1697 always dispatches.
1698 """
1699
1700 def NullCheck(name):
1701 return '%s === null' % name
1702
1703 def TypeCheck(name, type):
1704 return '%s is %s' % (name, type)
1705
1706 if position == len(info.arg_infos):
1707 if len(overloads) > 1:
1708 raise Exception('Duplicate operations ' + str(overloads))
1709 operation = overloads[0]
1710 self.GenerateSingleOperation(emitter, info, indent, operation)
1711 return False
1712
1713 # FIXME: Consider a simpler dispatch that iterates over the
1714 # overloads and generates an overload specific check. Revisit
1715 # when we move to named optional arguments.
1716
1717 # Partition the overloads to divide and conquer on the dispatch.
1718 positive = []
1719 negative = []
1720 first_overload = overloads[0]
1721 (param_name, param_type, param_default) = info.arg_infos[position]
1722
1723 if position < len(first_overload.arguments):
1724 # FIXME: This will not work if the second overload has a more
1725 # precise type than the first. E.g.,
1726 # void foo(Node x);
1727 # void foo(Element x);
1728 type = DartType(first_overload.arguments[position].type.id)
1729 test = TypeCheck(param_name, type)
1730 pred = lambda op: (len(op.arguments) > position and
1731 DartType(op.arguments[position].type.id) == type)
1732 else:
1733 type = None
1734 test = NullCheck(param_name)
1735 pred = lambda op: position >= len(op.arguments)
1736
1737 for overload in overloads:
1738 if pred(overload):
1739 positive.append(overload)
1740 else:
1741 negative.append(overload)
1742
1743 if positive and negative:
1744 (true_code, false_code) = emitter.Emit(
1745 '$(INDENT)if ($COND) {\n'
1746 '$!TRUE'
1747 '$(INDENT)} else {\n'
1748 '$!FALSE'
1749 '$(INDENT)}\n',
1750 COND=test, INDENT=indent)
1751 fallthrough1 = self.GenerateDispatch(
1752 true_code, info, indent + ' ', position + 1, positive)
1753 fallthrough2 = self.GenerateDispatch(
1754 false_code, info, indent + ' ', position, negative)
1755 return fallthrough1 or fallthrough2
1756
1757 if negative:
1758 raise Exception('Internal error, must be all positive')
1759
1760 # All overloads require the same test. Do we bother?
1761
1762 # If the test is the same as the method's formal parameter then checked mode
1763 # will have done the test already. (It could be null too but we ignore that
1764 # case since all the overload behave the same and we don't know which types
1765 # in the IDL are not nullable.)
1766 if type == param_type:
1767 return self.GenerateDispatch(
1768 emitter, info, indent, position + 1, positive)
1769
1770 # Otherwise the overloads have the same type but the type is a substype of
1771 # the method's synthesized formal parameter. e.g we have overloads f(X) and
1772 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The
1773 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee
1774 # that Y = Z-X, so we need to check for Y.
1775 true_code = emitter.Emit(
1776 '$(INDENT)if ($COND) {\n'
1777 '$!TRUE'
1778 '$(INDENT)}\n',
1779 COND=test, INDENT=indent)
1780 self.GenerateDispatch(
1781 true_code, info, indent + ' ', position + 1, positive)
1782 return True
OLDNEW
« no previous file with comments | « client/dom/scripts/systemfrog.py ('k') | client/dom/scripts/systeminterface.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698