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

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

Issue 9403004: Wrapperless dart:html generator (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review fixes Created 8 years, 10 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
(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 import os
10 from systembase import *
11 from systemfrog import *
12
13 # Members from the standard dom that should not be exposed publicly in dart:html
14 # but need to be exposed internally to implement dart:html on top of a standard
15 # browser.
16 _private_html_members = {
17 'Element': set(['clientLeft', 'clientTop', 'clientWidth', 'clientHeight',
18 'offsetLeft', 'offsetTop', 'offsetWidth', 'offsetHeight',
19 'scrollLeft', 'scrollTop', 'scrollWidth', 'scrollHeight',
20 'childElementCount', 'firstElementChild', 'hasAttribute',
21 'getAttribute', 'removeAttribute', 'setAttribute', 'className',
22 'children']),
23 'Node' : set(['appendChild', 'removeChild', 'replaceChild', 'attributes',
24 'childNodes']),
25 # TODO(jacobr): other direct translate methods on node such as
26 # textContext->text
27 'Document': set(['createElement', 'createEvent']),
28 'Window': set(['getComputedStyle']),
29 'EventTarget': set(['removeEventListener', 'addEventListener',
30 'dispatchEvent']),
31 'Event': set(['initEvent', 'target', 'srcElement', 'currentTarget'])
32 }
33
34 # Members from the standard dom that exist in the dart:html library with
35 # identical functionality but with cleaner names.
36 html_library_renames = {
37 'Document.createTextNode': 'Text.Text',
38 'Document.get:defaultView': 'Document.get:window',
39 'DocumentFragment.querySelector': 'Element.query',
40 'Element.querySelector': 'Element.query',
41 'Document.querySelector': 'Element.query',
42 'DocumentFragment.querySelectorAll': 'Element.queryAll',
43 'DocumentFragment.querySelectorAll': 'Element.queryAll',
44 'Element.querySelectorAll': 'Element.queryAll',
45 'Element.scrollIntoViewIfNeeded': 'Element.scrollIntoView',
46 'Node.cloneNode': 'Node.clone',
47 'Node.get:nextSibling': 'Node.get:nextNode',
48 'Node.get:ownerDocument': 'Node.get:document',
49 'Node.get:parentNode': 'Node.get:parent',
50 'Node.get:previousSibling': 'Node.get:previousNode',
51 }
52
53 # Members and classes from the dom that should be removed completelly from
54 # dart:html. These could be expressed in the IDL instead but expressing this
55 # as a simple table instead is more concise.
56 # TODO(jacobr): cleanup and augment this list.
57 _html_library_remove = set([
58 'Window.get:document', # Removed as we have a custom implementation.
59 'NodeList.item',
60 "Attr.*",
61 # "BarProp.*",
62 # "BarInfo.*",
63 # "Blob.webkitSlice",
64 # "CDATASection.*",
65 # "Comment.*",
66 # "DOMImplementation.*",
67 # TODO(jacobr): listing title here is a temporary hack due to a frog bug
68 # involving when an interface inherits from another interface and defines
69 # the same field. BUG(1633)
70 "Document.get:title",
71 "Document.set:title",
72 "Element.get:title",
73 "Element.set:title",
74 "Document.get:documentElement",
75 "Document.get:forms",
76 # "Document.get:selectedStylesheetSet",
77 # "Document.set:selectedStylesheetSet",
78 # "Document.get:preferredStylesheetSet",
79 "Document.get:links",
80 "Document.getElementsByTagName",
81 "Document.set:domain",
82 "Document.get:implementation",
83 "Document.createAttributeNS",
84 "Document.get:inputEncoding",
85 "Document.getElementsByClassName",
86 "Document.get:compatMode",
87 "Document.importNode",
88 "Document.evaluate",
89 "Document.get:images",
90 "Document.querySelector",
91 "Document.createExpression",
92 "Document.getOverrideStyle",
93 "Document.get:xmlStandalone",
94 "Document.set:xmlStandalone",
95 "Document.createComment",
96 "Document.adoptNode",
97 "Document.get:characterSet",
98 "Document.createAttribute",
99 "Document.querySelectorAll",
100 "Document.get:URL",
101 "Document.createElementNS",
102 "Document.createEntityReference",
103 "Document.get:documentURI",
104 "Document.set:documentURI",
105 "Document.createNodeIterator",
106 "Document.createProcessingInstruction",
107 "Document.get:doctype",
108 "Document.getElementsByName",
109 "Document.createTreeWalker",
110 "Document.get:location",
111 "Document.set:location",
112 "Document.createNSResolver",
113 "Document.get:xmlEncoding",
114 "Document.get:defaultCharset",
115 "Document.get:applets",
116 "Document.getSelection",
117 "Document.get:xmlVersion",
118 "Document.set:xmlVersion",
119 "Document.get:anchors",
120 "Document.getElementsByTagNameNS",
121 "DocumentType.*",
122 "Element.hasAttributeNS",
123 "Element.getAttributeNS",
124 "Element.setAttributeNode",
125 "Element.getAttributeNode",
126 "Element.removeAttributeNode",
127 "Element.removeAttributeNS",
128 "Element.setAttributeNodeNS",
129 "Element.getAttributeNodeNS",
130 "Element.setAttributeNS",
131 # "EventSource.get:url",
132 # TODO(jacobr): should these be removed?
133 "Document.close",
134 "Document.hasFocus",
135
136 "Document.get:vlinkColor",
137 "Document.set:vlinkColor",
138 "Document.captureEvents",
139 "Document.releaseEvents",
140 "Document.get:compatMode",
141 "Document.get:designMode",
142 "Document.set:designMode",
143 "Document.get:dir",
144 "Document.set:dir",
145 "Document.get:all",
146 "Document.set:all",
147 "Document.write",
148 "Document.get:fgColor",
149 "Document.set:fgColor",
150 "Document.get:bgColor",
151 "Document.set:bgColor",
152 "Document.get:plugins",
153 "Document.get:alinkColor",
154 "Document.set:alinkColor",
155 "Document.get:embeds",
156 "Document.open",
157 "Document.clear",
158 "Document.get:scripts",
159 "Document.writeln",
160 "Document.get:linkColor",
161 "Document.set:linkColor",
162 "Element.get:itemRef",
163 "Element.set:className",
164 "Element.get:outerText",
165 "Element.set:outerText",
166 "Element.get:accessKey",
167 "Element.set:accessKey",
168 "Element.get:itemType",
169 "Element.get:innerText",
170 "Element.set:innerText",
171 "Element.set:outerHTML",
172 "Element.get:itemScope",
173 "Element.set:itemScope",
174 "Element.get:itemValue",
175 "Element.set:itemValue",
176 "Element.get:itemId",
177 "Element.set:itemId",
178 "Element.get:itemProp",
179 "EmbedElement.getSVGDocument",
180 "FormElement.get:elements",
181 "HTMLFrameElement.*",
182 "HTMLFrameSetElement.*",
183 "HTMLHtmlElement.get:version",
184 "HTMLHtmlElement.set:version",
185 # "IFrameElement.getSVGDocument", #TODO(jacobr): should this be removed
186 "InputElement.get:dirName",
187 "InputElement.set:dirName",
188 "HTMLIsIndexElement.*",
189 "ObjectElement.getSVGDocument",
190 "HTMLOptionsCollection.*",
191 "HTMLPropertiesCollection.*",
192 "SelectElement.remove",
193 "TextAreaElement.get:dirName",
194 "TextAreaElement.set:dirName",
195 "NamedNodeMap.*",
196 "Node.isEqualNode",
197 "Node.get:TEXT_NODE",
198 "Node.hasAttributes",
199 "Node.get:DOCUMENT_TYPE_NODE",
200 "Node.get:DOCUMENT_POSITION_FOLLOWING",
201 "Node.get:childNodes",
202 "Node.lookupNamespaceURI",
203 "Node.get:ELEMENT_NODE",
204 "Node.get:namespaceURI",
205 "Node.get:DOCUMENT_FRAGMENT_NODE",
206 "Node.get:localName",
207 "Node.dispatchEvent",
208 "Node.isDefaultNamespace",
209 "Node.compareDocumentPosition",
210 "Node.get:baseURI",
211 "Node.isSameNode",
212 "Node.get:DOCUMENT_POSITION_DISCONNECTED",
213 "Node.get:DOCUMENT_NODE",
214 "Node.get:DOCUMENT_POSITION_CONTAINS",
215 "Node.get:COMMENT_NODE",
216 "Node.get:ENTITY_REFERENCE_NODE",
217 "Node.isSupported",
218 "Node.get:firstChild",
219 "Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC",
220 "Node.get:lastChild",
221 "Node.get:attributes",
222 "Node.get:NOTATION_NODE",
223 "Node.normalize",
224 "Node.get:parentElement",
225 "Node.get:ATTRIBUTE_NODE",
226 "Node.get:ENTITY_NODE",
227 "Node.get:DOCUMENT_POSITION_CONTAINED_BY",
228 "Node.get:prefix",
229 "Node.set:prefix",
230 "Node.get:DOCUMENT_POSITION_PRECEDING",
231 "Node.get:nodeType",
232 "Node.removeEventListener",
233 "Node.get:nodeValue",
234 "Node.set:nodeValue",
235 "Node.get:CDATA_SECTION_NODE",
236 "Node.get:nodeName",
237 "Node.addEventListener",
238 "Node.lookupPrefix",
239 "Node.get:PROCESSING_INSTRUCTION_NODE",
240 "Notification.dispatchEvent",
241 "Notification.addEventListener",
242 "Notification.removeEventListener"])
243
244 # Events without onEventName attributes in the IDL we want to support.
245 # We can automatically extract most event event names by checking for
246 # onEventName methods in the IDL but some events aren't listed so we need
247 # to manually add them here so that they are easy for users to find.
248 _html_manual_events = {
249 'Element': ['touchleave', 'webkitTransitionEnd'],
250 'Window': ['DOMContentLoaded']
251 }
252
253 # These event names must be camel case when attaching event listeners
254 # using addEventListener even though the onEventName properties in the DOM for
255 # them are not camel case.
256 _on_attribute_to_event_name_mapping = {
257 'webkitanimationend': 'webkitAnimationEnd',
258 'webkitanimationiteration': 'webkitAnimationIteration',
259 'webkitanimationstart': 'webkitAnimationStart',
260 'webkitfullscreenchange': 'webkitFullScreenChange',
261 'webkitfullscreenerror': 'webkitFullScreenError',
262 'webkitspeechchange': 'webkitSpeechChange',
263 'webkittransitionend': 'webkitTransitionEnd',
264 }
265
266 # Mapping from raw event names to the pretty camelCase event names exposed as
267 # properties in dart:html. If the DOM exposes a new event name, you will need
268 # to add the lower case to camel case conversion for that event name here.
269 _html_event_names = {
270 'DOMContentLoaded': 'contentLoaded',
271 'touchleave': 'touchLeave',
272 'abort': 'abort',
273 'beforecopy': 'beforeCopy',
274 'beforecut': 'beforeCut',
275 'beforepaste': 'beforePaste',
276 'beforeunload': 'beforeUnload',
277 'blur': 'blur',
278 'cached': 'cached',
279 'canplay': 'canPlay',
280 'canplaythrough': 'canPlayThrough',
281 'change': 'change',
282 'checking': 'checking',
283 'click': 'click',
284 'close': 'close',
285 'contextmenu': 'contextMenu',
286 'copy': 'copy',
287 'cut': 'cut',
288 'dblclick': 'doubleClick',
289 'devicemotion': 'deviceMotion',
290 'deviceorientation': 'deviceOrientation',
291 'display': 'display',
292 'downloading': 'downloading',
293 'drag': 'drag',
294 'dragend': 'dragEnd',
295 'dragenter': 'dragEnter',
296 'dragleave': 'dragLeave',
297 'dragover': 'dragOver',
298 'dragstart': 'dragStart',
299 'drop': 'drop',
300 'durationchange': 'durationChange',
301 'emptied': 'emptied',
302 'ended': 'ended',
303 'error': 'error',
304 'focus': 'focus',
305 'hashchange': 'hashChange',
306 'input': 'input',
307 'invalid': 'invalid',
308 'keydown': 'keyDown',
309 'keypress': 'keyPress',
310 'keyup': 'keyUp',
311 'load': 'load',
312 'loadeddata': 'loadedData',
313 'loadedmetadata': 'loadedMetadata',
314 'loadend': 'loadEnd',
315 'loadstart': 'loadStart',
316 'message': 'message',
317 'mousedown': 'mouseDown',
318 'mousemove': 'mouseMove',
319 'mouseout': 'mouseOut',
320 'mouseover': 'mouseOver',
321 'mouseup': 'mouseUp',
322 'mousewheel': 'mouseWheel',
323 'noupdate': 'noUpdate',
324 'obsolete': 'obsolete',
325 'offline': 'offline',
326 'online': 'online',
327 'open': 'open',
328 'pagehide': 'pageHide',
329 'pageshow': 'pageShow',
330 'paste': 'paste',
331 'pause': 'pause',
332 'play': 'play',
333 'playing': 'playing',
334 'popstate': 'popState',
335 'progress': 'progress',
336 'ratechange': 'rateChange',
337 'readystatechange': 'readyStateChange',
338 'reset': 'reset',
339 'resize': 'resize',
340 'scroll': 'scroll',
341 'search': 'search',
342 'seeked': 'seeked',
343 'seeking': 'seeking',
344 'select': 'select',
345 'selectionchange': 'selectionChange',
346 'selectstart': 'selectStart',
347 'show': 'show',
348 'stalled': 'stalled',
349 'storage': 'storage',
350 'submit': 'submit',
351 'suspend': 'suspend',
352 'timeupdate': 'timeUpdate',
353 'touchcancel': 'touchCancel',
354 'touchend': 'touchEnd',
355 'touchmove': 'touchMove',
356 'touchstart': 'touchStart',
357 'unload': 'unload',
358 'updateready': 'updateReady',
359 'volumechange': 'volumeChange',
360 'waiting': 'waiting',
361 'webkitAnimationEnd': 'animationEnd',
362 'webkitAnimationIteration': 'animationIteration',
363 'webkitAnimationStart': 'animationStart',
364 'webkitFullScreenChange': 'fullScreenChange',
365 'webkitFullScreenError': 'fullScreenError',
366 'webkitSpeechChange': 'speechChange',
367 'webkitTransitionEnd': 'transitionEnd'
368 }
369
370 def _OnAttributeToEventName(on_method):
371 event_name = on_method.id[2:]
372 if event_name in _on_attribute_to_event_name_mapping:
373 return _on_attribute_to_event_name_mapping[event_name]
374 else:
375 return event_name
376
377 def _DomToHtmlEvents(interface_id, events):
378 event_names = set(map(_OnAttributeToEventName, events))
379 if interface_id in _html_manual_events:
380 for manual_event_name in _html_manual_events[interface_id]:
381 event_names.add(manual_event_name)
382
383 return sorted(event_names, key=lambda name: _html_event_names[name])
384
385 # ------------------------------------------------------------------------------
386
387 class HtmlSystem(System):
388
389 def __init__(self, templates, database, emitters, output_dir, generator):
390 super(HtmlSystem, self).__init__(
391 templates, database, emitters, output_dir)
392 self._event_classes = set()
393 self._seen_event_names = {}
394 self._generator = generator
395
396 def _AllowInHtmlLibrary(self, interface, member):
397 if self._PrivateInHtmlLibrary(interface, member):
398 return False
399 for interface_name in ([interface.id] +
400 self._generator._AllImplementedInterfaces(interface)):
401 if interface.id + '.' + member in _html_library_remove:
402 return False
403 return True
404
405 def _PrivateInHtmlLibrary(self, interface, member):
406 for interface_name in ([interface.id] +
407 self._generator._AllImplementedInterfaces(interface)):
408 if (interface_name in _private_html_members and
409 member in _private_html_members[interface_name]):
410 return True
411 return False
412
413 # TODO(jacobr): this already exists
414 def _TraverseParents(self, interface, callback):
415 for parent in interface.parents:
416 parent_id = parent.type.id
417 if self._database.HasInterface(parent_id):
418 parent_interface = self._database.GetInterface(parent_id)
419 callback(parent_interface)
420 self._TraverseParents(parent_interface, callback)
421
422 # TODO(jacobr): this isn't quite right....
423 def _GetParentsEventsClasses(self, interface):
424 # Ugly hack as we don't specify that Document inherits from Element
425 # in our IDL.
426 if interface.id == 'Document':
427 return ['ElementEvents']
428
429 interfaces_with_events = set()
430 def visit(parent):
431 if parent.id in self._event_classes:
432 interfaces_with_events.add(parent)
433
434 self._TraverseParents(interface, visit)
435 if len(interfaces_with_events) == 0:
436 return ['Events']
437 else:
438 names = []
439 for interface in interfaces_with_events:
440 names.append(interface.id + 'Events')
441 return names
442
443 class HtmlInterfacesSystem(HtmlSystem):
444
445 def __init__(self, templates, database, emitters, output_dir, generator):
446 super(HtmlInterfacesSystem, self).__init__(
447 templates, database, emitters, output_dir, generator)
448 self._dart_interface_file_paths = []
449
450 def InterfaceGenerator(self,
451 interface,
452 common_prefix,
453 super_interface_name,
454 source_filter):
455 """."""
456 interface_name = interface.id
457 dart_interface_file_path = self._FilePathForDartInterface(interface_name)
458
459 self._dart_interface_file_paths.append(dart_interface_file_path)
460
461 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path)
462
463 template_file = 'interface_%s.darttemplate' % interface_name
464 template = self._templates.TryLoad(template_file)
465 if not template:
466 template = self._templates.Load('interface.darttemplate')
467
468 return HtmlDartInterfaceGenerator(
469 interface, dart_interface_code,
470 template,
471 common_prefix, super_interface_name,
472 source_filter, self)
473
474 def ProcessCallback(self, interface, info):
475 """Generates a typedef for the callback interface."""
476 interface_name = interface.id
477 file_path = self._FilePathForDartInterface(interface_name)
478 self._ProcessCallback(interface, info, file_path)
479
480 def GenerateLibraries(self, lib_dir):
481 pass
482
483
484 def _FilePathForDartInterface(self, interface_name):
485 """Returns the file path of the Dart interface definition."""
486 # TODO(jmesserly): is this the right path
487 return os.path.join(self._output_dir, 'html', 'interface',
488 '%s.dart' % interface_name)
489
490 # ------------------------------------------------------------------------------
491
492 # TODO(jmesserly): inheritance is probably not the right way to factor this long
493 # term, but it makes merging better for now.
494 class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
495 """Generates Dart Interface definition for one DOM IDL interface."""
496
497 def __init__(self, interface, emitter, template,
498 common_prefix, super_interface, source_filter, system):
499 super(HtmlDartInterfaceGenerator, self).__init__(interface,
500 emitter, template, common_prefix, super_interface, source_filter)
501 self._system = system
502
503 def StartInterface(self):
504 typename = self._interface.id
505
506 extends = []
507 suppressed_extends = []
508
509 for parent in self._interface.parents:
510 # TODO(vsm): Remove source_filter.
511 if MatchSourceFilter(self._source_filter, parent):
512 # Parent is a DOM type.
513 extends.append(parent.type.id)
514 elif '<' in parent.type.id:
515 # Parent is a Dart collection type.
516 # TODO(vsm): Make this check more robust.
517 extends.append(parent.type.id)
518 else:
519 suppressed_extends.append('%s.%s' %
520 (self._common_prefix, parent.type.id))
521
522 comment = ' extends'
523 extends_str = ''
524 if extends:
525 extends_str += ' extends ' + ', '.join(extends)
526 comment = ','
527 if suppressed_extends:
528 extends_str += ' /*%s %s */' % (comment, ', '.join(suppressed_extends))
529
530 if typename in interface_factories:
531 extends_str += ' default ' + interface_factories[typename]
532
533 # TODO(vsm): Add appropriate package / namespace syntax.
534 (self._members_emitter,
535 self._top_level_emitter) = self._emitter.Emit(
536 self._template + '$!TOP_LEVEL',
537 ID=typename,
538 EXTENDS=extends_str)
539
540 element_type = MaybeTypedArrayElementType(self._interface)
541 if element_type:
542 self._members_emitter.Emit(
543 '\n'
544 ' $CTOR(int length);\n'
545 '\n'
546 ' $CTOR.fromList(List<$TYPE> list);\n'
547 '\n'
548 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n',
549 CTOR=self._interface.id,
550 TYPE=element_type)
551
552 def AddAttribute(self, getter, setter):
553 if getter and not self._system._AllowInHtmlLibrary(self._interface,
554 'get:' + getter.id):
555 getter = None
556 if setter and not self._system._AllowInHtmlLibrary(self._interface,
557 'set:' + setter.id):
558 setter = None
559 if not getter and not setter:
560 return
561 if getter and setter and getter.type.id == setter.type.id:
562 self._members_emitter.Emit('\n $TYPE $NAME;\n',
563 NAME=getter.id, TYPE=getter.type.id);
564 return
565 if getter and not setter:
566 self._members_emitter.Emit('\n final $TYPE $NAME;\n',
567 NAME=getter.id, TYPE=getter.type.id);
568 return
569 raise Exception('Unexpected getter/setter combination %s %s' %
570 (getter, setter))
571
572 def AddOperation(self, info):
573 """
574 Arguments:
575 operations - contains the overloads, one or more operations with the same
576 name.
577 """
578 if self._system._AllowInHtmlLibrary(self._interface, info.name):
579 self._members_emitter.Emit('\n'
580 ' $TYPE $NAME($PARAMS);\n',
581 TYPE=info.type_name,
582 NAME=info.name,
583 PARAMS=info.ParametersInterfaceDeclaration())
584
585 def FinishInterface(self):
586 pass
587
588 def AddConstant(self, constant):
589 self._EmitConstant(self._members_emitter, constant)
590
591 def AddEventAttributes(self, event_attrs):
592 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
593 self._system._event_classes.add(self._interface.id)
594 events_interface = self._interface.id + 'Events'
595 self._members_emitter.Emit('\n $TYPE get on();\n',
596 TYPE=events_interface)
597 events_members = self._emitter.Emit(
598 '\ninterface $INTERFACE extends $PARENTS {\n$!MEMBERS}\n',
599 INTERFACE=events_interface,
600 PARENTS=', '.join(
601 self._system._GetParentsEventsClasses(self._interface)))
602
603 for event_name in event_attrs:
604 if event_name in _html_event_names:
605 events_members.Emit('\n EventListenerList get $NAME();\n',
606 NAME=_html_event_names[event_name])
607 else:
608 raise Exception('No known html even name for event: ' + event_name)
609
610 # ------------------------------------------------------------------------------
611
612 # TODO(jmesserly): inheritance is probably not the right way to factor this long
613 # term, but it makes merging better for now.
614 class HtmlFrogClassGenerator(FrogInterfaceGenerator):
615 """Generates a Frog class for the dart:html library from a DOM IDL
616 interface.
617 """
618
619 def __init__(self, system, interface, template, super_interface, dart_code):
620 super(HtmlFrogClassGenerator, self).__init__(
621 system, interface, template, super_interface, dart_code)
622
623
624 def StartInterface(self):
625 interface = self._interface
626 interface_name = interface.id
627
628 self._class_name = self._ImplClassName(interface_name)
629
630 base = None
631 if interface.parents:
632 supertype = interface.parents[0].type.id
633 # FIXME: We're currently injecting List<..> and EventTarget as
634 # supertypes in dart.idl. We should annotate/preserve as
635 # attributes instead. For now, this hack lets the interfaces
636 # inherit, but not the classes.
637 if (not IsDartListType(supertype) and
638 not supertype == 'EventTarget'):
639 base = self._ImplClassName(supertype)
640 if IsDartCollectionType(supertype):
641 # List methods are injected in AddIndexer.
642 pass
643 elif supertype == 'EventTarget':
644 # Most implementors of EventTarget specify the EventListener operations
645 # again. If the operations are not specified, try to inherit from the
646 # EventTarget implementation.
647 #
648 # Applies to MessagePort.
649 if not [op for op in interface.operations if op.id == 'addEventListener' ]:
650 base = self._ImplClassName(supertype)
651 else:
652 base = self._ImplClassName(supertype)
653
654 native_spec = MakeNativeSpec(interface.javascript_binding_name)
655
656 extends = ' extends ' + base if base else ''
657
658 # TODO: Include all implemented interfaces, including other Lists.
659 implements = [interface_name]
660 element_type = MaybeTypedArrayElementType(self._interface)
661 if element_type:
662 implements.append('List<' + element_type + '>')
663
664 self._members_emitter = self._dart_code.Emit(
665 self._template,
666 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
667 #$!MEMBERS
668 #}
669 CLASSNAME=self._class_name,
670 EXTENDS=extends,
671 IMPLEMENTS=' implements ' + ', '.join(implements),
672 NATIVESPEC=' native "' + native_spec + '"')
673
674 element_type = MaybeTypedArrayElementType(interface)
675 if element_type:
676 self.AddTypedArrayConstructors(element_type)
677
678 def AddAttribute(self, getter, setter):
679
680 if self._system._PrivateInHtmlLibrary(self._interface, getter.id):
681 if getter:
682 self._AddGetter(getter, True)
683 if setter:
684 self._AddSetter(setter, True)
685 return
686 if getter and not self._system._AllowInHtmlLibrary(self._interface,
687 'get:' + getter.id):
688 getter = None
689 if setter and not self._system._AllowInHtmlLibrary(self._interface,
690 'set:' + setter.id):
691 setter = None
692 if not getter and not setter:
693 return
694 # If the (getter, setter) pair is shadowing, we can't generate a shadowing
695 # field (Issue 1633).
696 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter)
697 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter)
698 if super_getter or super_setter:
699 if getter and not setter and super_getter and not super_setter:
700 if getter.type.id == super_getter.type.id:
701 # Compatible getter, use the superclass property. This works because
702 # JavaScript will do its own dynamic dispatch.
703 output_type = getter and self._NarrowOutputType(getter.type.id)
704 self._members_emitter.Emit(
705 '\n'
706 ' // Use implementation from $SUPER.\n'
707 ' // final $TYPE $NAME;\n',
708 SUPER=super_getter_interface.id,
709 NAME=getter.id, TYPE=output_type)
710 return
711
712 self._members_emitter.Emit('\n // Shadowing definition.')
713 if getter:
714 self._AddGetter(getter, False)
715 if setter:
716 self._AddSetter(setter, False)
717 return
718
719 if self._interface.id != 'Document':
720 output_type = getter and self._NarrowOutputType(getter.type.id)
721 input_type = setter and self._NarrowInputType(setter.type.id)
722 if getter and setter and input_type == output_type:
723 self._members_emitter.Emit(
724 '\n $TYPE $NAME;\n',
725 NAME=getter.id, TYPE=output_type)
726 return
727 if getter and not setter:
728 self._members_emitter.Emit(
729 '\n final $TYPE $NAME;\n',
730 NAME=getter.id, TYPE=output_type)
731 return
732 self._AddAttributeUsingProperties(getter, setter, False)
733
734 def _AddAttributeUsingProperties(self, getter, setter, private):
735 if getter:
736 self._AddGetter(getter, private)
737 if setter:
738 self._AddSetter(setter, private)
739
740 def _AddGetter(self, attr, private):
741 # TODO(sra): Remove native body when Issue 829 fixed.
742 self._members_emitter.Emit(
743 '\n $TYPE get $PRIVATE$NAME() native "return $THIS.$NAME;";\n',
744 NAME=attr.id, TYPE=self._NarrowOutputType(attr.type.id),
745 PRIVATE='_' if private else '',
746 THIS='this.parentNode' if self._interface.id == 'Document' else 'this'
747 )
748
749 def _AddSetter(self, attr, private):
750 # TODO(sra): Remove native body when Issue 829 fixed.
751 self._members_emitter.Emit(
752 '\n void set $PRIVATE$NAME($TYPE value)'
753 ' native "$THIS.$NAME = value;";\n',
754 NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id),
755 PRIVATE='_' if private else '',
756 THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
757
758 def AddOperation(self, info):
759 """
760 Arguments:
761 info: An OperationInfo object.
762 """
763 private_in_html = self._system._PrivateInHtmlLibrary(self._interface,
764 info.name)
765 if private_in_html or self._interface.id == 'Document':
766 # TODO(vsm): Handle overloads.
767 # TODO(jacobr): handle document more efficiently for cases where any
768 # document is fine. For example: use window.document instead of
769 # this.parentNode.
770 return_type = self._NarrowOutputType(info.type_name)
771 self._members_emitter.Emit(
772 '\n'
773 ' $TYPE $PRIVATE$NAME($PARAMS)'
774 ' native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n',
775 TYPE=return_type,
776 RETURN='' if return_type == 'void' else 'return ',
777 NAME=info.name,
778 PRIVATE='_' if private_in_html else '',
779 THIS='this.parentNode' if self._interface.id == 'Document'
780 else 'this',
781 PARAMNAMES=info.ParametersAsArgumentList(),
782 PARAMS=info.ParametersImplementationDeclaration(
783 lambda type_name: self._NarrowInputType(type_name)))
784 elif self._system._AllowInHtmlLibrary(self._interface, info.name):
785 # TODO(jacobr): this is duplicated from the parent class.
786 self._members_emitter.Emit(
787 '\n'
788 ' $TYPE $NAME($PARAMS) native;\n',
789 TYPE=self._NarrowOutputType(info.type_name),
790 NAME=info.name,
791 PARAMS=info.ParametersImplementationDeclaration(
792 lambda type_name: self._NarrowInputType(type_name)))
793
794 def AddEventAttributes(self, event_attrs):
795 event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
796 events_class = '_' + self._interface.id + 'EventsImpl'
797 events_interface = self._interface.id + 'Events'
798 self._members_emitter.Emit(
799 '\n $TYPE get on() =>\n new $TYPE($EVENTTARGET);\n',
800 TYPE=events_class,
801 EVENTTARGET='_jsDocument' if self._interface.id == 'Document'
802 else 'this')
803
804 self._system._event_classes.add(self._interface.id)
805
806 parent_event_classes = self._system._GetParentsEventsClasses(
807 self._interface)
808 if len(parent_event_classes) != 1:
809 raise Exception('Only one parent event class allowed '
810 + self._interface.id)
811
812 # TODO(jacobr): specify the type of _ptr as EventTarget
813 events_members = self._dart_code.Emit(
814 '\n'
815 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
816 ' $CLASSNAME(_ptr) : super(_ptr);\n'
817 '$!MEMBERS}\n',
818 TARGETCLASS=self._NarrowOutputType(self._interface.id),
819 CLASSNAME=events_class,
820 INTERFACE=events_interface,
821 SUPER='_' + parent_event_classes[0] + 'Impl')
822
823 for event_name in event_attrs:
824 if event_name in _html_event_names:
825 events_members.Emit(
826 "\n"
827 " EventListenerList get $NAME() => _get('$RAWNAME');\n",
828 RAWNAME=event_name,
829 NAME=_html_event_names[event_name])
830 else:
831 raise Exception('No known html even name for event: ' + event_name)
832
833 # ------------------------------------------------------------------------------
834
835 class HtmlFrogSystem(HtmlSystem):
836
837 def __init__(self, templates, database, emitters, output_dir, generator):
838 super(HtmlFrogSystem, self).__init__(
839 templates, database, emitters, output_dir, generator)
840 self._dart_frog_file_paths = []
841
842
843 def InterfaceGenerator(self,
844 interface,
845 common_prefix,
846 super_interface_name,
847 source_filter):
848 """."""
849 dart_frog_file_path = self._FilePathForFrogImpl(interface.id)
850 self._dart_frog_file_paths.append(dart_frog_file_path)
851
852 template_file = 'impl_%s.darttemplate' % interface.id
853 template = self._templates.TryLoad(template_file)
854 if not template:
855 template = self._templates.Load('frog_impl.darttemplate')
856
857 dart_code = self._emitters.FileEmitter(dart_frog_file_path)
858 return HtmlFrogClassGenerator(self, interface, template,
859 super_interface_name, dart_code)
860
861 def GenerateLibraries(self, lib_dir):
862 self._GenerateLibFile(
863 'html_frog.darttemplate',
864 os.path.join(lib_dir, 'html_frog.dart'),
865 (self._interface_system._dart_interface_file_paths +
866 self._interface_system._dart_callback_file_paths +
867 self._dart_frog_file_paths))
868
869 def Finish(self):
870 pass
871
872 def _FilePathForFrogImpl(self, interface_name):
873 """Returns the file path of the Frog implementation."""
874 # TODO(jmesserly): is this the right path
875 return os.path.join(self._output_dir, 'html', 'frog',
876 '%s.dart' % interface_name)
877
878 # ------------------------------------------------------------------------------
879
880 class WrappingInterfaceGenerator(object):
881 """Generates Dart and JS implementation for one DOM IDL interface."""
882
883 def __init__(self, interface, super_interface, dart_code, base_members):
884 """Generates Dart and JS code for the given interface.
885
886 Args:
887
888 interface: an IDLInterface instance. It is assumed that all types have
889 been converted to Dart types (e.g. int, String), unless they are in
890 the same package as the interface.
891 super_interface: A string or None, the name of the common interface that
892 this interface implements, if any.
893 dart_code: an Emitter for the file containing the Dart implementation
894 class.
895 base_members: a set of names of members defined in a base class. This is
896 used to avoid static member 'overriding' in the generated Dart code.
897 """
898 self._interface = interface
899 self._super_interface = super_interface
900 self._dart_code = dart_code
901 self._base_members = base_members
902 self._current_secondary_parent = None
903
904
905 def StartInterface(self):
906 interface = self._interface
907 interface_name = interface.id
908
909 self._class_name = self._ImplClassName(interface_name)
910
911 base = self._BaseClassName(interface)
912
913 (self._members_emitter,
914 self._top_level_emitter) = self._dart_code.Emit(
915 '\n'
916 'class $CLASS extends $BASE implements $INTERFACE {\n'
917 ' $CLASS() : super() {}\n'
918 '\n'
919 ' static create_$CLASS() native {\n'
920 ' return new $CLASS();\n'
921 ' }\n'
922 '$!MEMBERS'
923 '\n'
924 ' String get typeName() { return "$INTERFACE"; }\n'
925 '}\n'
926 '$!TOP_LEVEL',
927 CLASS=self._class_name, BASE=base, INTERFACE=interface_name)
928
929 def _ImplClassName(self, type_name):
930 return '_' + type_name + 'WrappingImplementation'
931
932 def _BaseClassName(self, interface):
933 if not interface.parents:
934 return 'DOMWrapperBase'
935
936 supertype = interface.parents[0].type.id
937
938 # FIXME: We're currently injecting List<..> and EventTarget as
939 # supertypes in dart.idl. We should annotate/preserve as
940 # attributes instead. For now, this hack lets the interfaces
941 # inherit, but not the classes.
942 # List methods are injected in AddIndexer.
943 if IsDartListType(supertype) or IsDartCollectionType(supertype):
944 return 'DOMWrapperBase'
945
946 if supertype == 'EventTarget':
947 # Most implementors of EventTarget specify the EventListener operations
948 # again. If the operations are not specified, try to inherit from the
949 # EventTarget implementation.
950 #
951 # Applies to MessagePort.
952 if not [op for op in interface.operations if op.id == 'addEventListener']:
953 return self._ImplClassName(supertype)
954 return 'DOMWrapperBase'
955
956 return self._ImplClassName(supertype)
957
958 def FinishInterface(self):
959 """."""
960 pass
961
962 def AddConstant(self, constant):
963 # Constants are already defined on the interface.
964 pass
965
966 def _MethodName(self, prefix, name):
967 method_name = prefix + name
968 if name in self._base_members: # Avoid illegal Dart 'static override'.
969 method_name = method_name + '_' + self._interface.id
970 return method_name
971
972 def AddAttribute(self, getter, setter):
973 if getter:
974 self._AddGetter(getter)
975 if setter:
976 self._AddSetter(setter)
977
978 def _AddGetter(self, attr):
979 # FIXME: Instead of injecting the interface name into the method when it is
980 # also implemented in the base class, suppress the method altogether if it
981 # has the same signature. I.e., let the JS do the virtual dispatch instead.
982 method_name = self._MethodName('_get_', attr.id)
983 self._members_emitter.Emit(
984 '\n'
985 ' $TYPE get $NAME() { return $METHOD(this); }\n'
986 ' static $TYPE $METHOD(var _this) native;\n',
987 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
988
989 def _AddSetter(self, attr):
990 # FIXME: See comment on getter.
991 method_name = self._MethodName('_set_', attr.id)
992 self._members_emitter.Emit(
993 '\n'
994 ' void set $NAME($TYPE value) { $METHOD(this, value); }\n'
995 ' static void $METHOD(var _this, $TYPE value) native;\n',
996 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
997
998 def AddSecondaryAttribute(self, interface, getter, setter):
999 self._SecondaryContext(interface)
1000 self.AddAttribute(getter, setter)
1001
1002 def AddSecondaryOperation(self, interface, info):
1003 self._SecondaryContext(interface)
1004 self.AddOperation(info)
1005
1006 def AddEventAttributes(self, event_attrs):
1007 pass
1008
1009 def _SecondaryContext(self, interface):
1010 if interface is not self._current_secondary_parent:
1011 self._current_secondary_parent = interface
1012 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id)
1013
1014 def AddIndexer(self, element_type):
1015 """Adds all the methods required to complete implementation of List."""
1016 # We would like to simply inherit the implementation of everything except
1017 # get length(), [], and maybe []=. It is possible to extend from a base
1018 # array implementation class only when there is no other implementation
1019 # inheritance. There might be no implementation inheritance other than
1020 # DOMBaseWrapper for many classes, but there might be some where the
1021 # array-ness is introduced by a non-root interface:
1022 #
1023 # interface Y extends X, List<T> ...
1024 #
1025 # In the non-root case we have to choose between:
1026 #
1027 # class YImpl extends XImpl { add List<T> methods; }
1028 #
1029 # and
1030 #
1031 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
1032 #
1033 if self._HasNativeIndexGetter(self._interface):
1034 self._EmitNativeIndexGetter(self._interface, element_type)
1035 else:
1036 self._members_emitter.Emit(
1037 '\n'
1038 ' $TYPE operator[](int index) {\n'
1039 ' return item(index);\n'
1040 ' }\n',
1041 TYPE=element_type)
1042
1043 if self._HasNativeIndexSetter(self._interface):
1044 self._EmitNativeIndexSetter(self._interface, element_type)
1045 else:
1046 self._members_emitter.Emit(
1047 '\n'
1048 ' void operator[]=(int index, $TYPE value) {\n'
1049 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
1050 ' }\n',
1051 TYPE=element_type)
1052
1053 self._members_emitter.Emit(
1054 '\n'
1055 ' void add($TYPE value) {\n'
1056 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1057 ' }\n'
1058 '\n'
1059 ' void addLast($TYPE value) {\n'
1060 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1061 ' }\n'
1062 '\n'
1063 ' void addAll(Collection<$TYPE> collection) {\n'
1064 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
1065 ' }\n'
1066 '\n'
1067 ' void sort(int compare($TYPE a, $TYPE b)) {\n'
1068 ' throw new UnsupportedOperationException("Cannot sort immutable List .");\n'
1069 ' }\n'
1070 '\n'
1071 ' void copyFrom(List<Object> src, int srcStart, '
1072 'int dstStart, int count) {\n'
1073 ' throw new UnsupportedOperationException("This object is immutable." );\n'
1074 ' }\n'
1075 '\n'
1076 ' int indexOf($TYPE element, [int start = 0]) {\n'
1077 ' return _Lists.indexOf(this, element, start, this.length);\n'
1078 ' }\n'
1079 '\n'
1080 ' int lastIndexOf($TYPE element, [int start = null]) {\n'
1081 ' if (start === null) start = length - 1;\n'
1082 ' return _Lists.lastIndexOf(this, element, start);\n'
1083 ' }\n'
1084 '\n'
1085 ' int clear() {\n'
1086 ' throw new UnsupportedOperationException("Cannot clear immutable Lis t.");\n'
1087 ' }\n'
1088 '\n'
1089 ' $TYPE removeLast() {\n'
1090 ' throw new UnsupportedOperationException("Cannot removeLast on immut able List.");\n'
1091 ' }\n'
1092 '\n'
1093 ' $TYPE last() {\n'
1094 ' return this[length - 1];\n'
1095 ' }\n'
1096 '\n'
1097 ' void forEach(void f($TYPE element)) {\n'
1098 ' _Collections.forEach(this, f);\n'
1099 ' }\n'
1100 '\n'
1101 ' Collection map(f($TYPE element)) {\n'
1102 ' return _Collections.map(this, [], f);\n'
1103 ' }\n'
1104 '\n'
1105 ' Collection<$TYPE> filter(bool f($TYPE element)) {\n'
1106 ' return _Collections.filter(this, new List<$TYPE>(), f);\n'
1107 ' }\n'
1108 '\n'
1109 ' bool every(bool f($TYPE element)) {\n'
1110 ' return _Collections.every(this, f);\n'
1111 ' }\n'
1112 '\n'
1113 ' bool some(bool f($TYPE element)) {\n'
1114 ' return _Collections.some(this, f);\n'
1115 ' }\n'
1116 '\n'
1117 ' void setRange(int start, int length, List<$TYPE> from, [int startFrom ]) {\n'
1118 ' throw new UnsupportedOperationException("Cannot setRange on immutab le List.");\n'
1119 ' }\n'
1120 '\n'
1121 ' void removeRange(int start, int length) {\n'
1122 ' throw new UnsupportedOperationException("Cannot removeRange on immu table List.");\n'
1123 ' }\n'
1124 '\n'
1125 ' void insertRange(int start, int length, [$TYPE initialValue]) {\n'
1126 ' throw new UnsupportedOperationException("Cannot insertRange on immu table List.");\n'
1127 ' }\n'
1128 '\n'
1129 ' List<$TYPE> getRange(int start, int length) {\n'
1130 ' throw new NotImplementedException();\n'
1131 ' }\n'
1132 '\n'
1133 ' bool isEmpty() {\n'
1134 ' return length == 0;\n'
1135 ' }\n'
1136 '\n'
1137 ' Iterator<$TYPE> iterator() {\n'
1138 ' return new _FixedSizeListIterator<$TYPE>(this);\n'
1139 ' }\n',
1140 TYPE=element_type)
1141
1142 def _HasNativeIndexGetter(self, interface):
1143 return ('HasIndexGetter' in interface.ext_attrs or
1144 'HasNumericIndexGetter' in interface.ext_attrs)
1145
1146 def _EmitNativeIndexGetter(self, interface, element_type):
1147 method_name = '_index'
1148 self._members_emitter.Emit(
1149 '\n'
1150 ' $TYPE operator[](int index) { return $METHOD(this, index); }\n'
1151 ' static $TYPE $METHOD(var _this, int index) native;\n',
1152 TYPE=element_type, METHOD=method_name)
1153
1154 def _HasNativeIndexSetter(self, interface):
1155 return 'HasCustomIndexSetter' in interface.ext_attrs
1156
1157 def _EmitNativeIndexSetter(self, interface, element_type):
1158 method_name = '_set_index'
1159 self._members_emitter.Emit(
1160 '\n'
1161 ' void operator[]=(int index, $TYPE value) {\n'
1162 ' return $METHOD(this, index, value);\n'
1163 ' }\n'
1164 ' static $METHOD(_this, index, value) native;\n',
1165 TYPE=element_type, METHOD=method_name)
1166
1167 def AddOperation(self, info):
1168 """
1169 Arguments:
1170 info: An OperationInfo object.
1171 """
1172 body = self._members_emitter.Emit(
1173 '\n'
1174 ' $TYPE $NAME($PARAMS) {\n'
1175 '$!BODY'
1176 ' }\n',
1177 TYPE=info.type_name,
1178 NAME=info.name,
1179 PARAMS=info.ParametersImplementationDeclaration())
1180
1181 # Process in order of ascending number of arguments to ensure missing
1182 # optional arguments are processed early.
1183 overloads = sorted(info.overloads,
1184 key=lambda overload: len(overload.arguments))
1185 self._native_version = 0
1186 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads)
1187 if fallthrough:
1188 body.Emit(' throw "Incorrect number or type of arguments";\n');
1189
1190 def GenerateSingleOperation(self, emitter, info, indent, operation):
1191 """Generates a call to a single operation.
1192
1193 Arguments:
1194 emitter: an Emitter for the body of a block of code.
1195 info: the compound information about the operation and its overloads.
1196 indent: an indentation string for generated code.
1197 operation: the IDLOperation to call.
1198 """
1199 # TODO(sra): Do we need to distinguish calling with missing optional
1200 # arguments from passing 'null' which is represented as 'undefined'?
1201 def UnwrapArgExpression(name, type):
1202 # TODO: Type specific unwrapping.
1203 return '__dom_unwrap(%s)' % (name)
1204
1205 def ArgNameAndUnwrapper(arg_info, overload_arg):
1206 (name, type, value) = arg_info
1207 return (name, UnwrapArgExpression(name, type))
1208
1209 names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg)
1210 for (i, arg) in enumerate(operation.arguments)]
1211 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers]
1212 arg_names = [name for (name, _) in names_and_unwrappers]
1213
1214 self._native_version += 1
1215 native_name = self._MethodName('_', info.name)
1216 if self._native_version > 1:
1217 native_name = '%s_%s' % (native_name, self._native_version)
1218
1219 argument_expressions = ', '.join(['this'] + arg_names)
1220 if info.type_name != 'void':
1221 emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n',
1222 INDENT=indent,
1223 NATIVENAME=native_name,
1224 ARGS=argument_expressions)
1225 else:
1226 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n'
1227 '$(INDENT)return;\n',
1228 INDENT=indent,
1229 NATIVENAME=native_name,
1230 ARGS=argument_expressions)
1231
1232 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n',
1233 NAME=native_name,
1234 TYPE=info.type_name,
1235 PARAMS=', '.join(['receiver'] + arg_names) )
1236
1237
1238 def GenerateDispatch(self, emitter, info, indent, position, overloads):
1239 """Generates a dispatch to one of the overloads.
1240
1241 Arguments:
1242 emitter: an Emitter for the body of a block of code.
1243 info: the compound information about the operation and its overloads.
1244 indent: an indentation string for generated code.
1245 position: the index of the parameter to dispatch on.
1246 overloads: a list of the remaining IDLOperations to dispatch.
1247
1248 Returns True if the dispatch can fall through on failure, False if the code
1249 always dispatches.
1250 """
1251
1252 def NullCheck(name):
1253 return '%s === null' % name
1254
1255 def TypeCheck(name, type):
1256 return '%s is %s' % (name, type)
1257
1258 if position == len(info.arg_infos):
1259 if len(overloads) > 1:
1260 raise Exception('Duplicate operations ' + str(overloads))
1261 operation = overloads[0]
1262 self.GenerateSingleOperation(emitter, info, indent, operation)
1263 return False
1264
1265 # FIXME: Consider a simpler dispatch that iterates over the
1266 # overloads and generates an overload specific check. Revisit
1267 # when we move to named optional arguments.
1268
1269 # Partition the overloads to divide and conquer on the dispatch.
1270 positive = []
1271 negative = []
1272 first_overload = overloads[0]
1273 (param_name, param_type, param_default) = info.arg_infos[position]
1274
1275 if position < len(first_overload.arguments):
1276 # FIXME: This will not work if the second overload has a more
1277 # precise type than the first. E.g.,
1278 # void foo(Node x);
1279 # void foo(Element x);
1280 type = first_overload.arguments[position].type.id
1281 test = TypeCheck(param_name, type)
1282 pred = lambda op: len(op.arguments) > position and op.arguments[position]. type.id == type
1283 else:
1284 type = None
1285 test = NullCheck(param_name)
1286 pred = lambda op: position >= len(op.arguments)
1287
1288 for overload in overloads:
1289 if pred(overload):
1290 positive.append(overload)
1291 else:
1292 negative.append(overload)
1293
1294 if positive and negative:
1295 (true_code, false_code) = emitter.Emit(
1296 '$(INDENT)if ($COND) {\n'
1297 '$!TRUE'
1298 '$(INDENT)} else {\n'
1299 '$!FALSE'
1300 '$(INDENT)}\n',
1301 COND=test, INDENT=indent)
1302 fallthrough1 = self.GenerateDispatch(
1303 true_code, info, indent + ' ', position + 1, positive)
1304 fallthrough2 = self.GenerateDispatch(
1305 false_code, info, indent + ' ', position, negative)
1306 return fallthrough1 or fallthrough2
1307
1308 if negative:
1309 raise Exception('Internal error, must be all positive')
1310
1311 # All overloads require the same test. Do we bother?
1312
1313 # If the test is the same as the method's formal parameter then checked mode
1314 # will have done the test already. (It could be null too but we ignore that
1315 # case since all the overload behave the same and we don't know which types
1316 # in the IDL are not nullable.)
1317 if type == param_type:
1318 return self.GenerateDispatch(
1319 emitter, info, indent, position + 1, positive)
1320
1321 # Otherwise the overloads have the same type but the type is a substype of
1322 # the method's synthesized formal parameter. e.g we have overloads f(X) and
1323 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The
1324 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee
1325 # that Y = Z-X, so we need to check for Y.
1326 true_code = emitter.Emit(
1327 '$(INDENT)if ($COND) {\n'
1328 '$!TRUE'
1329 '$(INDENT)}\n',
1330 COND=test, INDENT=indent)
1331 self.GenerateDispatch(
1332 true_code, info, indent + ' ', position + 1, positive)
1333 return True
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698