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

Side by Side Diff: sdk/lib/html/scripts/systemhtml.py

Issue 11691009: Moved most of html lib generating scripts into tools. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 12 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 | « sdk/lib/html/scripts/pegparser_test.py ('k') | sdk/lib/html/scripts/systemnative.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 emitter
10 import os
11 from generator import *
12 from htmldartgenerator import *
13
14 _js_custom_members = set([
15 'AudioBufferSourceNode.start',
16 'AudioBufferSourceNode.stop',
17 'AudioContext.createGain',
18 'AudioContext.createScriptProcessor',
19 'Console.memory',
20 'Console.profiles',
21 'Console.assertCondition',
22 'Console.count',
23 'Console.debug',
24 'Console.dir',
25 'Console.dirxml',
26 'Console.error',
27 'Console.group',
28 'Console.groupCollapsed',
29 'Console.groupEnd',
30 'Console.info',
31 'Console.log',
32 'Console.markTimeline',
33 'Console.profile',
34 'Console.profileEnd',
35 'Console.time',
36 'Console.timeEnd',
37 'Console.timeStamp',
38 'Console.trace',
39 'Console.warn',
40 'CSSStyleDeclaration.setProperty',
41 'Element.insertAdjacentElement',
42 'Element.insertAdjacentHTML',
43 'Element.insertAdjacentText',
44 'Element.remove',
45 'ElementEvents.mouseWheel',
46 'HTMLCanvasElement.getContext',
47 'HTMLTableElement.createTBody',
48 'IDBDatabase.transaction',
49 'KeyboardEvent.initKeyboardEvent',
50 'MouseEvent.offsetX',
51 'MouseEvent.offsetY',
52 'Navigator.language',
53 'URL.createObjectURL',
54 'URL.revokeObjectURL',
55 'WheelEvent.wheelDeltaX',
56 'WheelEvent.wheelDeltaY',
57 'Window.cancelAnimationFrame',
58 'Window.console',
59 'Window.document',
60 'Window.indexedDB',
61 'Window.location',
62 'Window.open',
63 'Window.requestAnimationFrame',
64 'Window.webkitCancelAnimationFrame',
65 'Window.webkitRequestAnimationFrame',
66 'WorkerContext.indexedDB',
67 ])
68
69
70 # Classes that offer only static methods, and therefore we should suppress
71 # constructor creation.
72 _static_classes = set(['Url'])
73
74 # Information for generating element constructors.
75 #
76 # TODO(sra): maybe remove all the argument complexity and use cascades.
77 #
78 # var c = new CanvasElement(width: 100, height: 70);
79 # var c = new CanvasElement()..width = 100..height = 70;
80 #
81 class ElementConstructorInfo(object):
82 def __init__(self, name=None, tag=None,
83 params=[], opt_params=[],
84 factory_provider_name='document'):
85 self.name = name # The constructor name 'h1' in 'HeadingElement.h1'
86 self.tag = tag or name # The HTML or SVG tag
87 self.params = params
88 self.opt_params = opt_params
89 self.factory_provider_name = factory_provider_name
90
91 def ConstructorInfo(self, interface_name):
92 info = OperationInfo()
93 info.overloads = None
94 info.declared_name = interface_name
95 info.name = interface_name
96 info.constructor_name = self.name
97 info.js_name = None
98 info.type_name = interface_name
99 info.param_infos = map(lambda tXn: ParamInfo(tXn[1], tXn[0], True),
100 self.opt_params)
101 info.requires_named_arguments = True
102 info.factory_parameters = ['"%s"' % self.tag]
103 info.pure_dart_constructor = True
104 return info
105
106 _html_element_constructors = {
107 'AnchorElement' :
108 ElementConstructorInfo(tag='a', opt_params=[('DOMString', 'href')]),
109 'AreaElement': 'area',
110 'ButtonElement': 'button',
111 'BRElement': 'br',
112 'BaseElement': 'base',
113 'BodyElement': 'body',
114 'ButtonElement': 'button',
115 'CanvasElement':
116 ElementConstructorInfo(tag='canvas',
117 opt_params=[('int', 'width'), ('int', 'height')]),
118 'ContentElement': 'content',
119 'DataListElement': 'datalist',
120 'DListElement': 'dl',
121 'DetailsElement': 'details',
122 'DivElement': 'div',
123 'EmbedElement': 'embed',
124 'FieldSetElement': 'fieldset',
125 'FormElement': 'form',
126 'HRElement': 'hr',
127 'HeadElement': 'head',
128 'HeadingElement': [ElementConstructorInfo('h1'),
129 ElementConstructorInfo('h2'),
130 ElementConstructorInfo('h3'),
131 ElementConstructorInfo('h4'),
132 ElementConstructorInfo('h5'),
133 ElementConstructorInfo('h6')],
134 'HtmlElement': 'html',
135 'IFrameElement': 'iframe',
136 'ImageElement':
137 ElementConstructorInfo(tag='img',
138 opt_params=[('DOMString', 'src'),
139 ('int', 'width'), ('int', 'height')]),
140 'KeygenElement': 'keygen',
141 'LIElement': 'li',
142 'LabelElement': 'label',
143 'LegendElement': 'legend',
144 'LinkElement': 'link',
145 'MapElement': 'map',
146 'MenuElement': 'menu',
147 'MeterElement': 'meter',
148 'OListElement': 'ol',
149 'ObjectElement': 'object',
150 'OptGroupElement': 'optgroup',
151 'OutputElement': 'output',
152 'ParagraphElement': 'p',
153 'ParamElement': 'param',
154 'PreElement': 'pre',
155 'ProgressElement': 'progress',
156 'ScriptElement': 'script',
157 'SelectElement': 'select',
158 'SourceElement': 'source',
159 'SpanElement': 'span',
160 'StyleElement': 'style',
161 'TableCaptionElement': 'caption',
162 'TableCellElement': 'td',
163 'TableColElement': 'col',
164 'TableElement': 'table',
165 'TableRowElement': 'tr',
166 #'TableSectionElement' <thead> <tbody> <tfoot>
167 'TextAreaElement': 'textarea',
168 'TitleElement': 'title',
169 'TrackElement': 'track',
170 'UListElement': 'ul',
171 'VideoElement': 'video'
172 }
173
174 _svg_element_constructors = {
175 'AElement': 'a',
176 'AnimateColorElement': 'animateColor',
177 'AnimateElement': 'animate',
178 'AnimateMotionElement': 'animateMotion',
179 'AnimateTransformElement': 'animateTransform',
180 'AnimationElement': 'animation',
181 'CircleElement': 'circle',
182 'ClipPathElement': 'clipPath',
183 'CursorElement': 'cursor',
184 'DefsElement': 'defs',
185 'DescElement': 'desc',
186 'EllipseElement': 'ellipse',
187 'FilterElement': 'filter',
188 'FontElement': 'font',
189 'FontFaceElement': 'font-face',
190 'FontFaceFormatElement': 'font-face-format',
191 'FontFaceNameElement': 'font-face-name',
192 'FontFaceSrcElement': 'font-face-src',
193 'FontFaceUriElement': 'font-face-uri',
194 'ForeignObjectElement': 'foreignObject',
195 'GlyphElement': 'glyph',
196 'GElement': 'g',
197 'HKernElement': 'hkern',
198 'ImageElement': 'image',
199 'LinearGradientElement': 'linearGradient',
200 'LineElement': 'line',
201 'MarkerElement': 'marker',
202 'MaskElement': 'mask',
203 'MPathElement': 'mpath',
204 'PathElement': 'path',
205 'PatternElement': 'pattern',
206 'PolygonElement': 'polygon',
207 'PolylineElement': 'polyline',
208 'RadialGradientElement': 'radialGradient',
209 'RectElement': 'rect',
210 'ScriptElement': 'script',
211 'SetElement': 'set',
212 'StopElement': 'stop',
213 'StyleElement': 'style',
214 'SwitchElement': 'switch',
215 'SymbolElement': 'symbol',
216 'TextElement': 'text',
217 'TitleElement': 'title',
218 'TRefElement': 'tref',
219 'TSpanElement': 'tspan',
220 'UseElement': 'use',
221 'ViewElement': 'view',
222 'VKernElement': 'vkern',
223 }
224
225 _element_constructors = {
226 'html': _html_element_constructors,
227 'indexed_db': {},
228 'svg': _svg_element_constructors,
229 'web_audio': {},
230 }
231
232 _factory_ctr_strings = {
233 'html': {
234 'provider_name': 'document',
235 'constructor_name': '$dom_createElement'
236 },
237 'indexed_db': {
238 'provider_name': 'document',
239 'constructor_name': '$dom_createElement'
240 },
241 'svg': {
242 'provider_name': '_SvgElementFactoryProvider',
243 'constructor_name': 'createSvgElement_tag',
244 },
245 'web_audio': {
246 'provider_name': 'document',
247 'constructor_name': '$dom_createElement'
248 },
249 }
250
251 def ElementConstructorInfos(typename, element_constructors,
252 factory_provider_name='_Elements'):
253 """Returns list of ElementConstructorInfos about the convenience constructors
254 for an Element or SvgElement."""
255 # TODO(sra): Handle multiple and named constructors.
256 if typename not in element_constructors:
257 return []
258 infos = element_constructors[typename]
259 if isinstance(infos, str):
260 infos = ElementConstructorInfo(tag=infos,
261 factory_provider_name=factory_provider_name)
262 if not isinstance(infos, list):
263 infos = [infos]
264 return infos
265
266 # ------------------------------------------------------------------------------
267
268 class HtmlDartInterfaceGenerator(object):
269 """Generates dart interface and implementation for the DOM IDL interface."""
270
271 def __init__(self, options, library_emitter, event_generator, interface,
272 backend):
273 self._renamer = options.renamer
274 self._database = options.database
275 self._template_loader = options.templates
276 self._type_registry = options.type_registry
277 self._options = options
278 self._library_emitter = library_emitter
279 self._event_generator = event_generator
280 self._interface = interface
281 self._backend = backend
282 self._interface_type_info = self._type_registry.TypeInfo(self._interface.id)
283 self._library_name = self._renamer.GetLibraryName(self._interface)
284
285 def Generate(self):
286 if 'Callback' in self._interface.ext_attrs:
287 self.GenerateCallback()
288 else:
289 self.GenerateInterface()
290
291 def GenerateCallback(self):
292 """Generates a typedef for the callback interface."""
293 handlers = [operation for operation in self._interface.operations
294 if operation.id == 'handleEvent']
295 info = AnalyzeOperation(self._interface, handlers)
296 code = self._library_emitter.FileEmitter(self._interface.id,
297 self._library_name)
298 code.Emit(self._template_loader.Load('callback.darttemplate'))
299
300 typedef_name = self._renamer.RenameInterface(self._interface)
301 code.Emit('typedef void $NAME($PARAMS);\n',
302 NAME=typedef_name,
303 PARAMS=info.ParametersDeclaration(self._DartType))
304 self._backend.GenerateCallback(info)
305
306 def GenerateInterface(self):
307 interface_name = self._interface_type_info.interface_name()
308
309 factory_provider = None
310 if interface_name in interface_factories:
311 factory_provider = interface_factories[interface_name]
312 factory_constructor_name = None
313
314 constructors = []
315 if interface_name in _static_classes:
316 constructor_info = None
317 else:
318 constructor_info = AnalyzeConstructor(self._interface)
319 if constructor_info:
320 constructors.append(constructor_info)
321 # TODO(antonm): consider removing it later.
322 factory_provider = interface_name
323
324 # HTML Elements and SVG Elements have convenience constructors.
325 infos = ElementConstructorInfos(interface_name,
326 _element_constructors[self._library_name], factory_provider_name=
327 _factory_ctr_strings[self._library_name]['provider_name'])
328
329 if infos:
330 factory_constructor_name = _factory_ctr_strings[
331 self._library_name]['constructor_name']
332
333 for info in infos:
334 constructors.append(info.ConstructorInfo(self._interface.id))
335 if factory_provider:
336 assert factory_provider == info.factory_provider_name
337 else:
338 factory_provider = info.factory_provider_name
339
340 implementation_emitter = self._ImplementationEmitter()
341
342 base_type_info = None
343 if self._interface.parents:
344 supertype = self._interface.parents[0].type.id
345 if not IsDartCollectionType(supertype) and not IsPureInterface(supertype):
346 base_type_info = self._type_registry.TypeInfo(supertype)
347 if base_type_info.merged_into() \
348 and self._backend.ImplementsMergedMembers():
349 base_type_info = self._type_registry.TypeInfo(
350 base_type_info.merged_into())
351
352 if base_type_info:
353 base_class = base_type_info.implementation_name()
354 else:
355 base_class = self._backend.RootClassName()
356
357 implements = self._backend.AdditionalImplementedInterfaces()
358 for parent in self._interface.parents:
359 parent_type_info = self._type_registry.TypeInfo(parent.type.id)
360 if parent_type_info.interface_name() != base_class and \
361 parent_type_info != base_type_info:
362 implements.append(parent_type_info.interface_name())
363
364 secure_base_name = self._backend.SecureBaseName(interface_name)
365 if secure_base_name:
366 implements.append(secure_base_name)
367
368 implements_str = ''
369 if implements:
370 implements_str = ' implements ' + ', '.join(set(implements))
371
372 annotations = FindCommonAnnotations(self._interface.doc_js_name)
373 annotations_str = ''
374 if annotations:
375 annotations_str = '\n' + '\n'.join(annotations)
376
377 self._implementation_members_emitter = implementation_emitter.Emit(
378 self._backend.ImplementationTemplate(),
379 LIBRARYNAME=self._library_name,
380 ANNOTATIONS=annotations_str,
381 CLASSNAME=self._interface_type_info.implementation_name(),
382 EXTENDS=' extends %s' % base_class if base_class else '',
383 IMPLEMENTS=implements_str,
384 DOMNAME=self._interface.doc_js_name,
385 NATIVESPEC=self._backend.NativeSpec())
386 self._backend.StartInterface(self._implementation_members_emitter)
387 self._backend.EmitHelpers(base_class)
388 self._backend.AddConstructors(
389 constructors, factory_provider, factory_constructor_name)
390
391 events_class_name = self._event_generator.ProcessInterface(
392 self._interface, interface_name,
393 self._backend.CustomJSMembers(),
394 implementation_emitter)
395 if events_class_name:
396 self._backend.EmitEventGetter(events_class_name)
397
398 merged_interface = self._interface_type_info.merged_interface()
399 if merged_interface:
400 self._backend.AddMembers(self._database.GetInterface(merged_interface),
401 not self._backend.ImplementsMergedMembers())
402
403 self._backend.AddMembers(self._interface)
404 self._backend.AddSecondaryMembers(self._interface)
405 self._backend.FinishInterface()
406
407 def _ImplementationEmitter(self):
408 basename = self._interface_type_info.implementation_name()
409 if (self._interface_type_info.merged_into() and
410 self._backend.ImplementsMergedMembers()):
411 # Merged members are implemented in target interface implementation.
412 return emitter.Emitter()
413 return self._library_emitter.FileEmitter(basename, self._library_name)
414
415 def _DartType(self, type_name):
416 return self._type_registry.DartType(type_name)
417
418
419 # ------------------------------------------------------------------------------
420
421 class Dart2JSBackend(HtmlDartGenerator):
422 """Generates a dart2js class for the dart:html library from a DOM IDL
423 interface.
424 """
425
426 def __init__(self, interface, options):
427 super(Dart2JSBackend, self).__init__(interface, options)
428
429 self._database = options.database
430 self._template_loader = options.templates
431 self._type_registry = options.type_registry
432 self._renamer = options.renamer
433 self._interface_type_info = self._type_registry.TypeInfo(self._interface.id)
434 self._current_secondary_parent = None
435
436 def ImplementsMergedMembers(self):
437 return True
438
439 def GenerateCallback(self, info):
440 pass
441
442 def RootClassName(self):
443 return None
444
445 def AdditionalImplementedInterfaces(self):
446 implements = super(Dart2JSBackend, self).AdditionalImplementedInterfaces()
447 if self._interface_type_info.list_item_type():
448 implements.append('JavaScriptIndexingBehavior')
449 return implements
450
451 def NativeSpec(self):
452 native_spec = MakeNativeSpec(self._interface.javascript_binding_name)
453 return ' native "%s"' % native_spec
454
455 def ImplementationTemplate(self):
456 if IsPureInterface(self._interface.id):
457 return self._template_loader.Load('pure_interface.darttemplate')
458
459 template_file = ('impl_%s.darttemplate' %
460 self._interface.doc_js_name)
461 return (self._template_loader.TryLoad(template_file) or
462 self._template_loader.Load('dart2js_impl.darttemplate'))
463
464 def StartInterface(self, members_emitter):
465 self._members_emitter = members_emitter
466
467 def FinishInterface(self):
468 pass
469
470 def EmitStaticFactory(self, constructor_info):
471 arguments = constructor_info.ParametersAsArgumentList()
472 if arguments:
473 arguments = ', ' + arguments
474 self._members_emitter.Emit(
475 " static $INTERFACE_NAME _create($PARAMETERS_DECLARATION) => JS("
476 "'$INTERFACE_NAME', "
477 "'new $CONSTRUCTOR_NAME($ARGUMENTS_PATTERN)'$ARGUMENTS);\n",
478 INTERFACE_NAME=self._interface_type_info.interface_name(),
479 PARAMETERS_DECLARATION=constructor_info.ParametersDeclaration(
480 self._DartType),
481 CONSTRUCTOR_NAME=constructor_info.name or self._interface.doc_js_name,
482 ARGUMENTS_PATTERN=','.join(['#'] * len(constructor_info.param_infos)),
483 ARGUMENTS=arguments)
484
485 def SecondaryContext(self, interface):
486 if interface is not self._current_secondary_parent:
487 self._current_secondary_parent = interface
488 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id)
489
490 def AddIndexer(self, element_type):
491 """Adds all the methods required to complete implementation of List."""
492 # We would like to simply inherit the implementation of everything except
493 # length, [], and maybe []=. It is possible to extend from a base
494 # array implementation class only when there is no other implementation
495 # inheritance. There might be no implementation inheritance other than
496 # DOMBaseWrapper for many classes, but there might be some where the
497 # array-ness is introduced by a non-root interface:
498 #
499 # interface Y extends X, List<T> ...
500 #
501 # In the non-root case we have to choose between:
502 #
503 # class YImpl extends XImpl { add List<T> methods; }
504 #
505 # and
506 #
507 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
508 #
509 self._members_emitter.Emit(
510 '\n'
511 ' $TYPE operator[](int index) => JS("$TYPE", "#[#]", this, index);\n',
512 TYPE=self.SecureOutputType(element_type))
513
514 if 'CustomIndexedSetter' in self._interface.ext_attrs:
515 self._members_emitter.Emit(
516 '\n'
517 ' void operator[]=(int index, $TYPE value) {'
518 ' JS("void", "#[#] = #", this, index, value); }',
519 TYPE=self._NarrowInputType(element_type))
520 else:
521 self._members_emitter.Emit(
522 '\n'
523 ' void operator[]=(int index, $TYPE value) {\n'
524 ' throw new UnsupportedError("Cannot assign element of immutable Li st.");\n'
525 ' }\n',
526 TYPE=self._NarrowInputType(element_type))
527
528 self.EmitListMixin(self._DartType(element_type))
529
530 def EmitAttribute(self, attribute, html_name, read_only):
531 if self._HasCustomImplementation(attribute.id):
532 return
533
534 if IsPureInterface(self._interface.id):
535 self._AddInterfaceAttribute(attribute, html_name)
536 return
537
538 # If the attribute is shadowing, we can't generate a shadowing
539 # field (Issue 1633).
540 # TODO(sra): _FindShadowedAttribute does not take into account the html
541 # renaming. we should be looking for another attribute that has the same
542 # html_name. Two attributes with the same IDL name might not match if one
543 # is renamed.
544 (super_attribute, super_attribute_interface) = self._FindShadowedAttribute(
545 attribute)
546 if super_attribute:
547 if read_only:
548 if attribute.type.id == super_attribute.type.id:
549 # Compatible attribute, use the superclass property. This works
550 # because JavaScript will do its own dynamic dispatch.
551 self._members_emitter.Emit(
552 '\n'
553 ' // Use implementation from $SUPER.\n'
554 ' // final $TYPE $NAME;\n',
555 SUPER=super_attribute_interface,
556 NAME=html_name,
557 TYPE=self.SecureOutputType(attribute.type.id))
558 return
559 self._members_emitter.Emit('\n // Shadowing definition.')
560 self._AddAttributeUsingProperties(attribute, html_name, read_only)
561 return
562
563 # If the type has a conversion we need a getter or setter to contain the
564 # conversion code.
565 if (self._OutputConversion(attribute.type.id, attribute.id) or
566 self._InputConversion(attribute.type.id, attribute.id)):
567 self._AddAttributeUsingProperties(attribute, html_name, read_only)
568 return
569
570 output_type = self.SecureOutputType(attribute.type.id)
571 input_type = self._NarrowInputType(attribute.type.id)
572 annotations = self._Annotations(attribute.type.id, attribute.id)
573 rename = self._RenamingAnnotation(attribute.id, html_name)
574 self.EmitAttributeDocumentation(attribute)
575 if not read_only:
576 self._members_emitter.Emit(
577 '\n $RENAME$ANNOTATIONS$TYPE $NAME;'
578 '\n',
579 RENAME=rename,
580 ANNOTATIONS=annotations,
581 NAME=html_name,
582 TYPE=output_type)
583 else:
584 template = '\n $RENAME$(ANNOTATIONS)final $TYPE $NAME;\n'
585 # Need to use a getter for list.length properties so we can add a
586 # setter which throws an exception, satisfying List API.
587 if self._interface_type_info.list_item_type() and html_name == 'length':
588 template = ('\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => ' +
589 'JS("$TYPE", "#.$NAME", this);\n')
590 self._members_emitter.Emit(
591 template,
592 RENAME=rename,
593 ANNOTATIONS=annotations,
594 NAME=html_name,
595 TYPE=output_type)
596
597 def _AddAttributeUsingProperties(self, attribute, html_name, read_only):
598 self._AddRenamingGetter(attribute, html_name)
599 if not read_only:
600 self._AddRenamingSetter(attribute, html_name)
601
602 def _AddInterfaceAttribute(self, attribute, html_name):
603 self._members_emitter.Emit(
604 '\n $TYPE $NAME;'
605 '\n',
606 NAME=html_name,
607 TYPE=self.SecureOutputType(attribute.type.id))
608
609 def _AddRenamingGetter(self, attr, html_name):
610 self.EmitAttributeDocumentation(attr)
611
612 conversion = self._OutputConversion(attr.type.id, attr.id)
613 if conversion:
614 return self._AddConvertingGetter(attr, html_name, conversion)
615 return_type = self.SecureOutputType(attr.type.id)
616 native_type = self._NarrowToImplementationType(attr.type.id)
617 self._members_emitter.Emit(
618 # TODO(sra): Use metadata to provide native name.
619 '\n $TYPE get $HTML_NAME => JS("$NATIVE_TYPE", "#.$NAME", this);'
620 '\n',
621 HTML_NAME=html_name,
622 NAME=attr.id,
623 TYPE=return_type,
624 NATIVE_TYPE=native_type)
625
626 def _AddRenamingSetter(self, attr, html_name):
627 self.EmitAttributeDocumentation(attr)
628
629 conversion = self._InputConversion(attr.type.id, attr.id)
630 if conversion:
631 return self._AddConvertingSetter(attr, html_name, conversion)
632 self._members_emitter.Emit(
633 # TODO(sra): Use metadata to provide native name.
634 '\n void set $HTML_NAME($TYPE value) {'
635 '\n JS("void", "#.$NAME = #", this, value);'
636 '\n }'
637 '\n',
638 HTML_NAME=html_name,
639 NAME=attr.id,
640 TYPE=self._NarrowInputType(attr.type.id))
641
642 def _AddConvertingGetter(self, attr, html_name, conversion):
643 self._members_emitter.Emit(
644 '\n $RETURN_TYPE get $HTML_NAME => $CONVERT(this._$(HTML_NAME));'
645 "\n @JSName('$NAME')"
646 '\n $(ANNOTATIONS)final $NATIVE_TYPE _$HTML_NAME;'
647 '\n',
648 ANNOTATIONS=self._Annotations(attr.type.id, html_name),
649 CONVERT=conversion.function_name,
650 HTML_NAME=html_name,
651 NAME=attr.id,
652 RETURN_TYPE=conversion.output_type,
653 NATIVE_TYPE=conversion.input_type)
654
655 def _AddConvertingSetter(self, attr, html_name, conversion):
656 self._members_emitter.Emit(
657 # TODO(sra): Use metadata to provide native name.
658 '\n void set $HTML_NAME($INPUT_TYPE value) {'
659 '\n this._$HTML_NAME = $CONVERT(value);'
660 '\n }'
661 '\n void set _$HTML_NAME(/*$NATIVE_TYPE*/ value) {'
662 '\n JS("void", "#.$NAME = #", this, value);'
663 '\n }'
664 '\n',
665 CONVERT=conversion.function_name,
666 HTML_NAME=html_name,
667 NAME=attr.id,
668 INPUT_TYPE=conversion.input_type,
669 NATIVE_TYPE=conversion.output_type)
670
671 def AmendIndexer(self, element_type):
672 pass
673
674 def EmitOperation(self, info, html_name):
675 """
676 Arguments:
677 info: An OperationInfo object.
678 """
679 if self._HasCustomImplementation(info.name):
680 return
681
682 self.EmitOperationDocumentation(info)
683
684 if IsPureInterface(self._interface.id):
685 self._AddInterfaceOperation(info, html_name)
686 elif any(self._OperationRequiresConversions(op) for op in info.overloads):
687 # Any conversions needed?
688 self._AddOperationWithConversions(info, html_name)
689 else:
690 self._AddDirectNativeOperation(info, html_name)
691
692 def _AddDirectNativeOperation(self, info, html_name):
693 self._members_emitter.Emit(
694 '\n'
695 ' $RENAME$ANNOTATIONS$MODIFIERS$TYPE $NAME($PARAMS) native;\n',
696 RENAME=self._RenamingAnnotation(info.declared_name, html_name),
697 ANNOTATIONS=self._Annotations(info.type_name, info.declared_name),
698 MODIFIERS='static ' if info.IsStatic() else '',
699 TYPE=self.SecureOutputType(info.type_name),
700 NAME=html_name,
701 PARAMS=info.ParametersDeclaration(self._NarrowInputType))
702
703 def _AddOperationWithConversions(self, info, html_name):
704 # Assert all operations have same return type.
705 assert len(set([op.type.id for op in info.operations])) == 1
706 output_conversion = self._OutputConversion(info.type_name,
707 info.declared_name)
708 if output_conversion:
709 return_type = output_conversion.output_type
710 native_return_type = output_conversion.input_type
711 else:
712 return_type = self._NarrowInputType(info.type_name)
713 native_return_type = return_type
714
715 def InputType(type_name):
716 conversion = self._InputConversion(type_name, info.declared_name)
717 if conversion:
718 return conversion.input_type
719 else:
720 return self._NarrowInputType(type_name) if type_name else 'dynamic'
721
722 body = self._members_emitter.Emit(
723 '\n'
724 ' $MODIFIERS$TYPE $(HTML_NAME)($PARAMS) {\n'
725 '$!BODY'
726 ' }\n',
727 MODIFIERS='static ' if info.IsStatic() else '',
728 TYPE=return_type,
729 HTML_NAME=html_name,
730 PARAMS=info.ParametersDeclaration(InputType))
731
732 parameter_names = [param_info.name for param_info in info.param_infos]
733 parameter_types = [InputType(param_info.type_id)
734 for param_info in info.param_infos]
735 operations = info.operations
736
737 method_version = [0]
738 temp_version = [0]
739
740 def GenerateCall(operation, argument_count, checks):
741 if checks:
742 (stmts_emitter, call_emitter) = body.Emit(
743 ' if ($CHECKS) {\n$!STMTS$!CALL }\n',
744 INDENT=' ',
745 CHECKS=' &&\n '.join(checks))
746 else:
747 (stmts_emitter, call_emitter) = body.Emit('$!A$!B', INDENT=' ');
748
749 method_version[0] += 1
750 target = '_%s_%d' % (html_name, method_version[0]);
751 arguments = []
752 target_parameters = []
753 for position, arg in enumerate(operation.arguments[:argument_count]):
754 conversion = self._InputConversion(arg.type.id, operation.id)
755 param_name = operation.arguments[position].id
756 if conversion:
757 temp_version[0] += 1
758 temp_name = '%s_%s' % (param_name, temp_version[0])
759 temp_type = conversion.output_type
760 stmts_emitter.Emit(
761 '$(INDENT)$TYPE $NAME = $CONVERT($ARG);\n',
762 TYPE=TypeOrVar(temp_type),
763 NAME=temp_name,
764 CONVERT=conversion.function_name,
765 ARG=parameter_names[position])
766 arguments.append(temp_name)
767 param_type = temp_type
768 verified_type = temp_type # verified by assignment in checked mode.
769 else:
770 arguments.append(parameter_names[position])
771 param_type = self._NarrowInputType(arg.type.id)
772 # Verified by argument checking on entry to the dispatcher.
773
774 verified_type = InputType(info.param_infos[position].type_id)
775 # The native method does not need an argument type if we know the type .
776 # But we do need the native methods to have correct function types, so
777 # be conservative.
778 if param_type == verified_type:
779 if param_type in ['String', 'num', 'int', 'double', 'bool', 'Object' ]:
780 param_type = 'dynamic'
781
782 target_parameters.append(
783 '%s%s' % (TypeOrNothing(param_type), param_name))
784
785 argument_list = ', '.join(arguments)
786 # TODO(sra): If the native method has zero type checks, we can 'inline' is
787 # and call it directly with a JS-expression.
788 call = '%s(%s)' % (target, argument_list)
789
790 if output_conversion:
791 call = '%s(%s)' % (output_conversion.function_name, call)
792
793 if operation.type.id == 'void':
794 call_emitter.Emit('$(INDENT)$CALL;\n$(INDENT)return;\n',
795 CALL=call)
796 else:
797 call_emitter.Emit('$(INDENT)return $CALL;\n', CALL=call)
798
799 self._members_emitter.Emit(
800 ' $RENAME$ANNOTATIONS$MODIFIERS$TYPE$TARGET($PARAMS) native;\n',
801 RENAME=self._RenamingAnnotation(info.declared_name, target),
802 ANNOTATIONS=self._Annotations(info.type_name, info.declared_name),
803 MODIFIERS='static ' if info.IsStatic() else '',
804 TYPE=TypeOrNothing(native_return_type),
805 TARGET=target,
806 PARAMS=', '.join(target_parameters))
807
808 def GenerateChecksAndCall(operation, argument_count):
809 checks = []
810 for i in range(0, argument_count):
811 argument = operation.arguments[i]
812 parameter_name = parameter_names[i]
813 test_type = self._DartType(argument.type.id)
814 if test_type in ['dynamic', 'Object']:
815 checks.append('?%s' % parameter_name)
816 elif test_type != parameter_types[i]:
817 checks.append('(?%s && (%s is %s || %s == null))' % (
818 parameter_name, parameter_name, test_type, parameter_name))
819
820 checks.extend(['!?%s' % name for name in parameter_names[argument_count:]] )
821 # There can be multiple presence checks. We need them all since a later
822 # optional argument could have been passed by name, leaving 'holes'.
823 GenerateCall(operation, argument_count, checks)
824
825 # TODO: Optimize the dispatch to avoid repeated checks.
826 if len(operations) > 1:
827 for operation in operations:
828 for position, argument in enumerate(operation.arguments):
829 if self._IsOptional(operation, argument):
830 GenerateChecksAndCall(operation, position)
831 GenerateChecksAndCall(operation, len(operation.arguments))
832 body.Emit(
833 ' throw new ArgumentError("Incorrect number or type of arguments"); '
834 '\n');
835 else:
836 operation = operations[0]
837 argument_count = len(operation.arguments)
838 for position, argument in list(enumerate(operation.arguments))[::-1]:
839 if self._IsOptional(operation, argument):
840 check = '?%s' % parameter_names[position]
841 GenerateCall(operation, position + 1, [check])
842 argument_count = position
843 GenerateCall(operation, argument_count, [])
844
845 def _AddInterfaceOperation(self, info, html_name):
846 self._members_emitter.Emit(
847 '\n'
848 ' $TYPE $NAME($PARAMS);\n',
849 TYPE=self.SecureOutputType(info.type_name),
850 NAME=info.name,
851 PARAMS=info.ParametersDeclaration(self._NarrowInputType))
852
853 def _IsOptional(self, operation, argument):
854 return IsOptional(argument)
855
856
857 def _OperationRequiresConversions(self, operation):
858 return (self._OperationRequiresOutputConversion(operation) or
859 self._OperationRequiresInputConversions(operation))
860
861 def _OperationRequiresOutputConversion(self, operation):
862 return self._OutputConversion(operation.type.id, operation.id)
863
864 def _OperationRequiresInputConversions(self, operation):
865 return any(self._InputConversion(arg.type.id, operation.id)
866 for arg in operation.arguments)
867
868 def _OutputConversion(self, idl_type, member):
869 return FindConversion(idl_type, 'get', self._interface.id, member)
870
871 def _InputConversion(self, idl_type, member):
872 return FindConversion(idl_type, 'set', self._interface.id, member)
873
874 def _HasCustomImplementation(self, member_name):
875 member_name = '%s.%s' % (self._interface.doc_js_name, member_name)
876 return member_name in _js_custom_members
877
878 def _RenamingAnnotation(self, idl_name, member_name):
879 if member_name != idl_name:
880 return "@JSName('%s')\n " % idl_name
881 return ''
882
883 def _Annotations(self, idl_type, idl_member_name):
884 annotations = FindDart2JSAnnotations(idl_type, self._interface.id,
885 idl_member_name)
886 if annotations:
887 return '%s\n ' % annotations
888 return_type = self.SecureOutputType(idl_type)
889 native_type = self._NarrowToImplementationType(idl_type)
890 if native_type != return_type:
891 return "@Returns('%s') @Creates('%s')\n " % (native_type, native_type)
892 else:
893 return ''
894
895 def CustomJSMembers(self):
896 return _js_custom_members
897
898 def _NarrowToImplementationType(self, type_name):
899 return self._type_registry.TypeInfo(type_name).narrow_dart_type()
900
901 def _NarrowInputType(self, type_name):
902 return self._NarrowToImplementationType(type_name)
903
904 def _FindShadowedAttribute(self, attr):
905 """Returns (attribute, superinterface) or (None, None)."""
906 def FindInParent(interface):
907 """Returns matching attribute in parent, or None."""
908 if interface.parents:
909 parent = interface.parents[0]
910 if IsDartCollectionType(parent.type.id):
911 return (None, None)
912 if IsPureInterface(parent.type.id):
913 return (None, None)
914 if self._database.HasInterface(parent.type.id):
915 interfaces_to_search_in = []
916 parent_interface_name = parent.type.id
917 interfaces_to_search_in.append(parent_interface_name)
918 parent_type_info = self._type_registry.TypeInfo(parent_interface_name)
919 if parent_type_info.merged_into():
920 # IDL parent was merged into another interface, which became a
921 # parent interface in Dart.
922 parent_interface_name = parent_type_info.merged_into()
923 interfaces_to_search_in.append(parent_interface_name)
924 elif parent_type_info.merged_interface():
925 # IDL parent has another interface that was merged into it.
926 interfaces_to_search_in.append(parent_type_info.merged_interface())
927
928 for interface_name in interfaces_to_search_in:
929 interface = self._database.GetInterface(interface_name)
930 attr2 = FindMatchingAttribute(interface, attr)
931 if attr2:
932 return (attr2, parent_interface_name)
933
934 return FindInParent(
935 self._database.GetInterface(parent_interface_name))
936 return (None, None)
937
938 return FindInParent(self._interface) if attr else (None, None)
939
940 def _DartType(self, type_name):
941 return self._type_registry.DartType(type_name)
942
943 # ------------------------------------------------------------------------------
944
945 class DartLibraryEmitter():
946 def __init__(self, multiemitter, dart_sources_dir, dart_libraries):
947 self._multiemitter = multiemitter
948 self._dart_sources_dir = dart_sources_dir
949 self._path_to_emitter = {}
950 self._dart_libraries = dart_libraries
951
952 def FileEmitter(self, basename, library_name, template=None):
953 aux_dir = os.path.join(self._dart_sources_dir, library_name)
954 path = os.path.join(aux_dir, '%s.dart' % basename)
955 if not path in self._path_to_emitter:
956 emitter = self._multiemitter.FileEmitter(path)
957 if not template is None:
958 emitter = emitter.Emit(template)
959 self._path_to_emitter[path] = emitter
960
961 self._dart_libraries.AddFile(basename, library_name, path)
962 return self._path_to_emitter[path]
963
964 def EmitLibraries(self, auxiliary_dir):
965 self._dart_libraries.Emit(self._multiemitter, auxiliary_dir)
966
967 # ------------------------------------------------------------------------------
968 class DartLibrary():
969 def __init__(self, name, template_loader, library_type, output_dir):
970 self._template = template_loader.Load(
971 '%s_%s.darttemplate' % (name, library_type))
972 self._dart_path = os.path.join(
973 output_dir, '%s_%s.dart' % (name, library_type))
974 self._paths = []
975
976 def AddFile(self, path):
977 self._paths.append(path)
978
979 def Emit(self, emitter, auxiliary_dir):
980 def massage_path(path):
981 # The most robust way to emit path separators is to use / always.
982 return path.replace('\\', '/')
983
984 library_emitter = emitter.FileEmitter(self._dart_path)
985 library_file_dir = os.path.dirname(self._dart_path)
986 auxiliary_dir = os.path.relpath(auxiliary_dir, library_file_dir)
987 imports_emitter = library_emitter.Emit(
988 self._template, AUXILIARY_DIR=massage_path(auxiliary_dir))
989
990 for path in sorted(self._paths):
991 relpath = os.path.relpath(path, library_file_dir)
992 imports_emitter.Emit(
993 "part '$PATH';\n", PATH=massage_path(relpath))
994
995 # ------------------------------------------------------------------------------
996
997 class DartLibraries():
998 def __init__(self, libraries, template_loader, library_type, output_dir):
999 self._libraries = {}
1000 for library_name in libraries:
1001 self._libraries[library_name] = DartLibrary(
1002 library_name, template_loader, library_type, output_dir)
1003
1004 def AddFile(self, basename, library_name, path):
1005 self._libraries[library_name].AddFile(path)
1006
1007 def Emit(self, emitter, auxiliary_dir):
1008 for lib in self._libraries.values():
1009 lib.Emit(emitter, auxiliary_dir)
OLDNEW
« no previous file with comments | « sdk/lib/html/scripts/pegparser_test.py ('k') | sdk/lib/html/scripts/systemnative.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698