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

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