Flutter Engine
The Flutter Engine
htmldartgenerator.py
Go to the documentation of this file.
1#!/usr/bin/env python3
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"""This module provides shared functionality for the system to generate
6dart:html APIs from the IDL database."""
7
8import emitter
9from generator import AnalyzeOperation, ConstantOutputOrder, \
10 DartDomNameOfAttribute, FindMatchingAttribute, IsPureInterface, \
11 TypeOrNothing, ConvertToFuture, GetCallbackInfo
12from copy import deepcopy
13from htmlrenamer import convert_to_future_members, custom_html_constructors, \
14 GetDDC_Extension, keep_overloaded_members, overloaded_and_renamed,\
15 private_html_members, renamed_html_members, renamed_overloads, \
16 removed_html_members
17from generator import TypeOrVar
18import logging
19from mdnreader import MDNReader
20import monitored
21import sys
22
23_logger = logging.getLogger('htmldartgenerator')
24
25# Types that are accessible cross-frame in a limited fashion.
26# In these cases, the base type (e.g., WindowBase) provides restricted access
27# while the subtype (e.g., Window) provides full access to the
28# corresponding objects if there are from the same frame.
29_secure_base_types = {
30 'Window': 'WindowBase',
31 'Location': 'LocationBase',
32 'History': 'HistoryBase',
33}
34
35_custom_factories = [
36 'Notification',
37 'EventSource',
38]
39
40class HtmlDartGenerator(object):
41
42 def __init__(self, interface, options, dart_use_blink, logger):
43 self._dart_use_blink = dart_use_blink
44 self._database = options.database
45 self._interface = interface
46 self._type_registry = options.type_registry
47 self._interface_type_info = self._type_registry.TypeInfo(
48 self._interface.id)
49 self._renamer = options.renamer
50 self._metadata = options.metadata
51 self._library_name = self._renamer.GetLibraryName(self._interface)
52 self._mdn_reader = MDNReader()
53 _logger.setLevel(logger.level)
54
56 if self.HasSupportCheck():
57 check = self.GetSupportCheck()
58 if type(check) != tuple:
59 signature = 'get supported'
60 else:
61 signature = check[0]
62 check = check[1]
63 self._members_emitter.Emit(
64 '\n'
65 ' /// Checks if this type is supported on the current platform.\n'
66 ' static bool $SIGNATURE => $SUPPORT_CHECK;\n',
67 SIGNATURE=signature,
68 SUPPORT_CHECK=check)
69
70 def EmitEventGetter(self, events_class_name):
71 self._members_emitter.Emit(
72 "EventTarget.removeEventListener, EventTarget.dispatchEvent')"
73 "\n @deprecated"
74 "\n $TYPE get on =>\n new $TYPE(this);\n",
75 TYPE=events_class_name)
76
77 def AddMembers(self, interface, declare_only=False, dart_js_interop=False):
78 if self._interface.id == 'WebGLRenderingContextBase' or self._interface.id == 'WebGL2RenderingContextBase' or \
79 self._interface.id == 'WebGLDrawBuffers':
80 # Constants in classes WebGLRenderingContextBase, WebGL2RenderingContext, WebGLDrawBuffers are consolidated into
81 # one synthesized class (WebGL).
82 self._gl_constants.extend(interface.constants)
83 else:
84 for const in sorted(interface.constants, key=ConstantOutputOrder):
85 self.AddConstant(const)
86
87 for attr in sorted(interface.attributes, key=ConstantOutputOrder):
88 if attr.type.id != 'EventHandler' and attr.type.id != 'EventListener':
89 self.AddAttribute(attr, declare_only)
90
91 # The implementation should define an indexer if the interface directly
92 # extends List.
93 element_type = None
94 requires_indexer = False
95 if self._interface_type_info.list_item_type():
96 self.AddIndexer(self._interface_type_info.list_item_type(),
97 self._interface_type_info.list_item_type_nullable())
98 else:
99 for parent in self._database.Hierarchy(self._interface):
100 if parent == self._interface:
101 continue
102 parent_type_info = self._type_registry.TypeInfo(parent.id)
103 if parent_type_info.list_item_type():
104 self.AmendIndexer(parent_type_info.list_item_type())
105 break
106
107 # Group overloaded operations by name.
108 self._AddRenamedOverloads(interface)
109 operationsByName = self._OperationsByName(interface)
110 if self.OmitOperationOverrides():
112 operationsByName, interface)
113
114 # Generate operations.
115 for id in sorted(operationsByName.keys()):
116 operations = operationsByName[id]
117 info = AnalyzeOperation(interface, operations)
118 self.AddOperation(info, declare_only, dart_js_interop)
119 if ('%s.%s' % (interface.id,
120 info.declared_name) in convert_to_future_members):
121 self.AddOperation(ConvertToFuture(info), declare_only)
122
123 def AddSecondaryMembers(self, interface):
124 secondary_parents = self._database.TransitiveSecondaryParents(
125 interface, not self._dart_use_blink)
126 remove_duplicate_parents = list(set(secondary_parents))
127 if len(secondary_parents) != len(remove_duplicate_parents):
128 secondary_parents = remove_duplicate_parents
129 parent_list = ", ".join(
130 [" %s" % (parent.id) for parent in secondary_parents])
131 _logger.warn('Interface %s has duplicate parent interfaces %s - ' \
132 'ignoring duplicates. Please file a bug with the dart:html team.' % (interface.id, parent_list))
133
134 for parent_interface in sorted(secondary_parents,
135 key=ConstantOutputOrder):
136 if isinstance(parent_interface, str):
137 continue
138
139 for attr in sorted(parent_interface.attributes,
140 key=ConstantOutputOrder):
141 if not FindMatchingAttribute(interface, attr):
142 if attr.type.id != 'EventHandler':
143 self.SecondaryContext(parent_interface)
144 self.AddAttribute(attr)
145
146 # Group overloaded operations by name.
147 operationsByName = self._OperationsByName(parent_interface)
148
149 if self.OmitOperationOverrides():
151 operationsByName, interface)
152
153 # Generate operations.
154 for id in sorted(operationsByName.keys()):
155 if not any(op.id == id for op in interface.operations):
156 operations = operationsByName[id]
157 info = AnalyzeOperation(interface, operations)
158 self.SecondaryContext(parent_interface)
159 self.AddOperation(info)
160
161 def _RemoveShadowingOperationsWithSameSignature(self, operationsByName,
162 interface):
163 if not interface.parents:
164 return
165
166 parent_name = interface.parents[0].type.id
167 parent = self._database.GetInterface(parent_name)
168 if parent == self._interface or parent == interface:
169 return
170
171 # Never remove operations that are added as a result of an implements they
172 # are pure interfaces (mixins to this interface).
173 if (IsPureInterface(parent_name, self._database)):
174 return
175 for operation in parent.operations:
176 if operation.id in operationsByName:
177 operations = operationsByName[operation.id]
178 for existing_operation in operations:
179 if existing_operation.SameSignatureAs(operation):
180 del operationsByName[operation.id]
181
182 def _AddRenamedOverloads(self, interface):
183 """The IDL has a number of functions with the same name but that accept
184 different types. This is fine for JavaScript, but results in vague type
185 signatures for Dart. We rename some of these (by adding a new identical
186 operation with a different DartName), but leave the original version as
187 well in some cases."""
188 potential_added_operations = set()
189 operations_by_name = self._OperationsByName(interface)
190 already_renamed = [
191 operation.ext_attrs['DartName']
192 if 'DartName' in operation.ext_attrs else ''
193 for operation in interface.operations
194 ]
195
196 added_operations = []
197 for operation in interface.operations:
198 full_operation_str = self._GetStringRepresentation(
199 interface, operation)
200 if (full_operation_str in renamed_overloads and
201 renamed_overloads[full_operation_str] not in already_renamed
202 ):
203 if '%s.%s' % (interface.id,
204 operation.id) in overloaded_and_renamed:
205 cloned_operation = deepcopy(operation)
206 cloned_operation.ext_attrs['DartName'] = renamed_overloads[
207 full_operation_str]
208 added_operations.append(cloned_operation)
209 else:
210 dart_name = renamed_overloads[full_operation_str]
211 if not dart_name:
212 continue
213
214 operation.ext_attrs['DartName'] = dart_name
215 potential_added_operations.add(operation.id)
216 self._EnsureNoMultipleTypeSignatures(interface, operation,
217 operations_by_name)
218 interface.operations += added_operations
219 self._AddDesiredOverloadedOperations(potential_added_operations,
220 interface, operations_by_name)
221
222 def _AddDesiredOverloadedOperations(self, potential_added_operations,
223 interface, original_operations_by_name):
224 """For some cases we desire to keep the overloaded version in dart, for
225 simplicity of API, and explain the parameters accepted in documentation."""
226 updated_operations_by_name = self._OperationsByName(interface)
227 for operation_id in potential_added_operations:
228 if (operation_id not in updated_operations_by_name and '%s.%s' %
229 (interface.id, operation_id) in keep_overloaded_members):
230 for operation in original_operations_by_name[operation_id]:
231 cloned_operation = deepcopy(operation)
232 cloned_operation.ext_attrs['DartName'] = operation_id
233 interface.operations.append(cloned_operation)
234
235 def _EnsureNoMultipleTypeSignatures(self, interface, operation,
236 operations_by_name):
237 """Make sure that there is now at most one operation with a particular
238 operation.id. If not, stop library generation, and throw an error, requiring
239 programmer input about the best name change before proceeding."""
240 operation_str = '%s.%s' % (interface.id, operation.id)
241
242 if (operation.id in operations_by_name and
243 len(operations_by_name[operation.id]) > 1 and len(
244 list(
245 filter(
246 lambda overload: overload.startswith(operation_str),
247 renamed_overloads.keys()))) == 0 and
248 operation_str not in keep_overloaded_members and
249 operation_str not in overloaded_and_renamed and
250 operation_str not in renamed_html_members and
251 operation_str not in private_html_members and
252 operation_str not in removed_html_members and
253 operation.id != '__getter__' and
254 operation.id != '__setter__' and operation.id != '__delete__'):
255 _logger.warn(
256 'Multiple type signatures for %s.%s. Please file a bug with'
257 ' the dart:html team to determine if one of these functions should be'
258 ' renamed.' % (interface.id, operation.id))
259
260 def _GetStringRepresentation(self, interface, operation):
261 """Given an IDLOperation, return a object-independent representation of the
262 operations's signature."""
263 return '%s.%s(%s)' % (interface.id, operation.id, ', '.join(
264 ['%s %s' % (arg.type.id, arg.id) for arg in operation.arguments]))
265
266 def _OperationsByName(self, interface):
267 operationsByName = {}
268 for operation in interface.operations:
269 name = operation.ext_attrs.get('DartName', operation.id)
270 operationsByName.setdefault(name, []).append(operation)
271 return operationsByName
272
274 return False
275
276 def AddConstant(self, constant):
277 const_name = self._renamer.RenameMember(
278 self._interface.id,
279 constant,
280 constant.id,
281 'get:',
282 dartify_name=False)
283 if not const_name:
284 return
285
286 annotations = self._metadata.GetFormattedMetadata(
287 self._library_name, self._interface, constant.id, ' ')
288
289 type = TypeOrNothing(self._DartType(constant.type.id), constant.type.id)
290 self._members_emitter.Emit(
291 '\n $(ANNOTATIONS)static const $TYPE$NAME = $VALUE;\n',
292 ANNOTATIONS=annotations,
293 NAME=const_name,
294 TYPE=type,
295 VALUE=constant.value)
296
297 def AddAttribute(self, attribute, declare_only=False):
298 """ Adds an attribute to the generated class.
299 Arguments:
300 attribute - The attribute which is to be added.
301 declare_only- True if the attribute should be declared as an abstract
302 member and not include invocation code.
303 """
304 dom_name = DartDomNameOfAttribute(attribute)
305 attr_name = self._renamer.RenameMember(self._interface.id, attribute,
306 dom_name, 'get:')
307 if not attr_name:
308 return
309
310 html_setter_name = self._renamer.RenameMember(
311 self._interface.id, attribute, dom_name, 'set:')
312 read_only = (attribute.is_read_only or
313 'Replaceable' in attribute.ext_attrs or
314 not html_setter_name)
315
316 # We don't yet handle inconsistent renames of the getter and setter yet.
317 assert (not html_setter_name or attr_name == html_setter_name)
318
319 # any is assumed to be nullable
320 if attribute.type.id == 'any':
321 attribute.type.nullable = True
322
323 if declare_only:
324 self.DeclareAttribute(attribute, attr_name, read_only)
325 else:
326 self.EmitAttribute(attribute, attr_name, read_only)
327
328 def AddOperation(self, info, declare_only=False, dart_js_interop=False):
329 # TODO(terry): Hack window has 2 overloaded getter one returns Window and
330 # and other object (we'll always return Window)?
331 if self._interface.id == "Window" and info.name == '__getter__':
332 info.operations[1].type = info.operations[0].type
333 """ Adds an operation to the generated class.
334 Arguments:
335 info - The operation info of the operation to be added.
336 declare_only- True if the operation should be declared as an abstract
337 member and not include invocation code.
338 """
339 # FIXME: When we pass in operations[0] below, we're assuming all
340 # overloaded operations have the same security attributes. This
341 # is currently true, but we should consider filtering earlier or
342 # merging the relevant data into info itself.
343 method_name = self._renamer.RenameMember(
344 self._interface.id, info.operations[0], info.name, 'call:')
345 if not method_name:
346 if info.name == 'item':
347 # FIXME: item should be renamed to operator[], not removed.
348 self.EmitOperation(info, '_item')
349 return
350
351 if declare_only:
352 self.DeclareOperation(info,
353 self.SecureOutputType(info.type_name,
354 nullable=info.type_nullable),
355 method_name)
356 else:
357 self.EmitOperation(info, method_name, dart_js_interop)
358
359 def _GenerateOverloadDispatcher(
360 self,
361 info,
362 signatures,
363 is_void,
364 declaration,
365 generate_call,
366 is_optional,
367 emitter,
368 can_omit_type_check=lambda type, pos: False):
369
370 parameter_names = [p.name for p in info.param_infos]
371 number_of_required_in_dart = info.NumberOfRequiredInDart()
372
373 body_emitter = emitter.Emit('\n'
374 ' $DECLARATION {\n'
375 '$!BODY'
376 ' }\n',
377 DECLARATION=declaration)
378
379 version = [0]
380
381 def GenerateCall(signature_index, argument_count, checks):
382 if checks:
383 (stmts_emitter, call_emitter) = body_emitter.Emit(
384 ' if ($CHECKS) {\n$!STMTS$!CALL }\n',
385 INDENT=' ',
386 CHECKS=' && '.join(checks))
387 else:
388 (stmts_emitter, call_emitter) = body_emitter.Emit(
389 '$!STMTS$!CALL', INDENT=' ')
390
391 if is_void:
392 call_emitter = call_emitter.Emit(
393 '$(INDENT)$!CALL;\n$(INDENT)return;\n')
394 else:
395 call_emitter = call_emitter.Emit('$(INDENT)return $!CALL;\n')
396
397 version[0] += 1
398 generate_call(stmts_emitter, call_emitter, version[0],
399 signature_index, argument_count)
400
401 def IsTypeChecking(interface_argument):
402 return 'LegacyInterfaceTypeChecking' in interface_argument.ext_attrs or \
403 self._database.HasInterface(interface_argument.id)
404
405 def GenerateChecksAndCall(signature_index, argument_count):
406 checks = []
407 typechecked_interface = IsTypeChecking(self._interface)
408
409 for i in reversed(range(0, argument_count)):
410 argument = signatures[signature_index][i]
411 parameter_name = parameter_names[i]
412
413 test_type = self._NarrowToImplementationType(argument.type.id)
414
415 if test_type in ['dynamic', 'Object']:
416 checks.append('%s != null' % parameter_name)
417 elif not can_omit_type_check(test_type, i):
418 typechecked = typechecked_interface or IsTypeChecking(
419 argument)
420 converts_null = \
421 ('TreatNullAs' in argument.ext_attrs) or \
422 (argument.default_value is not None) or \
423 (argument.default_value_is_null)
424 if argument.type.nullable or converts_null or not typechecked:
425 checks.append(
426 '(%s is %s || %s == null)' %
427 (parameter_name, test_type, parameter_name))
428 else:
429 checks.append(
430 '(%s is %s)' % (parameter_name, test_type))
431 elif i >= number_of_required_in_dart and not argument.type.nullable:
432 checks.append('%s != null' % parameter_name)
433
434 # There can be multiple presence checks. We need them all since a later
435 # optional argument could have been passed by name, leaving 'holes'.
436 checks.extend([
437 '%s == null' % name for name in parameter_names[argument_count:]
438 ])
439
440 GenerateCall(signature_index, argument_count, checks)
441
442 # TODO: Optimize the dispatch to avoid repeated checks.
443 if len(signatures) > 1:
444 index_swaps = {}
445 for signature_index, signature in enumerate(signatures):
446 for argument_position, argument in enumerate(signature):
447 if argument.type.id != 'ArrayBuffer':
448 continue
449 candidates = enumerate(signatures[signature_index + 1:],
450 signature_index + 1)
451 for candidate_index, candidate in candidates:
452 if len(candidate) <= argument_position:
453 continue
454 if candidate[
455 argument_position].type.id != 'ArrayBufferView':
456 continue
457 if len(index_swaps):
458 raise Exception(
459 'Cannot deal with more than a single swap')
460 index_swaps[candidate_index] = signature_index
461 index_swaps[signature_index] = candidate_index
462
463 for signature_index in range(len(signatures)):
464 signature_index = index_swaps.get(signature_index,
465 signature_index)
466 signature = signatures[signature_index]
467 for argument_position, argument in enumerate(signature):
468 if is_optional(signature_index, argument):
469 GenerateChecksAndCall(signature_index,
470 argument_position)
471 GenerateChecksAndCall(signature_index, len(signature))
472 body_emitter.Emit(
473 ' throw new ArgumentError("Incorrect number or type of arguments");'
474 '\n')
475 else:
476 signature = signatures[0]
477 argument_count = len(signature)
478 for argument_position, argument in list(enumerate(signature))[::-1]:
479 if is_optional(0, argument):
480 check = '%s != null' % parameter_names[argument_position]
481 # argument_count instead of argument_position + 1 is used here to cover one
482 # complicated case with the effectively optional argument in the middle.
483 # Consider foo(x, optional y, [Default=NullString] optional z)
484 # (as of now it's modelled after HTMLMediaElement.webkitAddKey).
485 # y is optional in WebCore, while z is not.
486 # In this case, if y was actually passed, we'd like to emit foo(x, y, z) invocation,
487 # not foo(x, y).
488 GenerateCall(0, argument_count, [check])
489 argument_count = argument_position
490 GenerateCall(0, argument_count, [])
491
492 def _GenerateDispatcherBody(self,
493 info,
494 operations,
495 declaration,
496 generate_call,
497 is_optional,
498 can_omit_type_check=lambda type, pos: False):
499
500 def GenerateCall(stmts_emitter, call_emitter, version, signature_index,
501 argument_count):
502 generate_call(stmts_emitter, call_emitter, version,
503 operations[signature_index], argument_count)
504
505 def IsOptional(signature_index, argument):
506 return is_optional(argument)
507
508 emitter = self._members_emitter
509
511 info, [operation.arguments for operation in operations],
512 operations[0].type.id == 'void', declaration, GenerateCall,
513 IsOptional, emitter, can_omit_type_check)
514
516 # TODO: Include all implemented interfaces, including other Lists.
517 implements = []
518 if self._interface_type_info.list_item_type():
519 item_type = self._type_registry.TypeInfo(
520 self._interface_type_info.list_item_type()).dart_type()
521 if self._interface_type_info.list_item_type_nullable():
522 item_type += '?'
523 implements.append('List<%s>' % item_type)
524 return implements
525
526 def Mixins(self):
527 mixins = []
528 if self._interface_type_info.list_item_type():
529 item_type = self._type_registry.TypeInfo(
530 self._interface_type_info.list_item_type()).dart_type()
531 if self._interface_type_info.list_item_type_nullable():
532 item_type += '?'
533 mixins.append('ListMixin<%s>' % item_type)
534 mixins.append('ImmutableListMixin<%s>' % item_type)
535
536 return mixins
537
538 def AddConstructors(self, constructors, factory_name,
539 factory_constructor_name, constructor_emitter):
540 """ Adds all of the constructors.
541 Arguments:
542 constructors - List of the constructors to be added.
543 factory_name - Name of the factory for this class.
544 factory_constructor_name - The name of the constructor on the
545 factory_name to call (calls an autogenerated FactoryProvider
546 if unspecified)
547 constructor_emitter - Emitter used to emit constructors when generating
548 classes using the static extension pattern.
549 """
550 for constructor_info in constructors:
551 self._AddConstructor(constructor_info, factory_name,
552 factory_constructor_name, constructor_emitter)
553
554 def _AddConstructor(self, constructor_info, factory_name,
555 factory_constructor_name, constructor_emitter):
556 # Hack to ignore the constructor used by JavaScript.
557 if ((self._interface.id == 'HTMLImageElement' or
558 self._interface.id == 'Blob' or
559 self._interface.id == 'DOMException') and
560 not constructor_info.pure_dart_constructor):
561 return
562
563 if self.GenerateCustomFactory(constructor_info):
564 return
565
566 metadata = self._metadata.GetFormattedMetadata(
567 self._library_name, self._interface, self._interface.id, ' ')
568
569 target_emitter = constructor_emitter if constructor_emitter else \
570 self._members_emitter
571
572 if not factory_constructor_name:
573 factory_constructor_name = '_create'
574 factory_parameters = constructor_info.ParametersAsArgumentList()
575 else:
576 factory_parameters = ', '.join(constructor_info.factory_parameters)
577
578 def InputType(type_name):
579 conversion = self._InputConversion(type_name,
580 constructor_info.declared_name)
581 if conversion:
582 return conversion.input_type
583 else:
584 return self._NarrowInputType(
585 type_name) if type_name else 'dynamic'
586
587 if constructor_info.pure_dart_constructor:
588 # TODO(antonm): use common dispatcher generation for this case as well.
589 has_optional = any(param_info.is_optional
590 for param_info in constructor_info.param_infos)
591 factory_call = self.MakeFactoryCall(
592 factory_name, factory_constructor_name, factory_parameters,
593 constructor_info)
594 if not has_optional:
595 target_emitter.Emit(
596 '\n $(METADATA)'
597 'factory $CTOR($PARAMS) => '
598 '$FACTORY_CALL;\n',
599 CTOR=constructor_info._ConstructorFullName(self._DartType),
600 PARAMS=constructor_info.ParametersAsDeclaration(InputType),
601 FACTORY_CALL=factory_call,
602 METADATA=metadata)
603 else:
604 inits = target_emitter.Emit(
605 '\n $(METADATA)'
606 'factory $CONSTRUCTOR($PARAMS) {\n'
607 ' $CONSTRUCTOR e = $FACTORY_CALL;\n'
608 '$!INITS'
609 ' return e;\n'
610 ' }\n',
611 CONSTRUCTOR=constructor_info._ConstructorFullName(
612 self._DartType),
613 METADATA=metadata,
614 FACTORY_CALL=factory_call,
615 PARAMS=constructor_info.ParametersAsDeclaration(InputType))
616
617 for index, param_info in enumerate(
618 constructor_info.param_infos):
619 if param_info.is_optional:
620 inits.Emit(
621 ' if ($E != null) e.$E = $E;\n',
622 E=param_info.name)
623 else:
624 custom_factory_ctr = self._interface.id in _custom_factories
625 if self._interface_type_info.has_generated_interface():
626 constructor_full_name = constructor_info._ConstructorFullName(
627 self._DartType)
628 else:
629 # The interface is suppress_interface so use the implementation_name not
630 # the dart_type.
631 constructor_full_name = self._interface_type_info.implementation_name(
632 )
633 factory_name = constructor_full_name
634
635 def GenerateCall(stmts_emitter, call_emitter, version,
636 signature_index, argument_count):
637 name = emitter.Format('_create_$VERSION', VERSION=version)
638 arguments = constructor_info.idl_args[
639 signature_index][:argument_count]
640 args = None
641 call_template = ''
642 if self._dart_use_blink:
643 type_ids = [p.type.id for p in arguments]
644 base_name, rs = \
645 self.DeriveNativeEntry("constructorCallback", 'Constructor', argument_count)
646 qualified_name = \
647 self.DeriveQualifiedBlinkName(self._interface.id,
648 base_name)
649 args = constructor_info.ParametersAsArgumentList(
650 argument_count)
651
652 # Handle converting Maps to Dictionaries, etc.
653 (factory_params, converted_arguments,
654 calling_params) = self._ConvertArgumentTypes(
655 stmts_emitter, arguments, argument_count,
656 constructor_info)
657 args = ', '.join(converted_arguments)
658 call_template = '$FACTORY_NAME($FACTORY_PARAMS)'
659 else:
660 qualified_name = emitter.Format(
661 '$FACTORY.$NAME', FACTORY=factory_name, NAME=name)
662 (factory_params, converted_arguments,
663 calling_params) = self._ConvertArgumentTypes(
664 stmts_emitter, arguments, argument_count,
665 constructor_info)
666 args = ', '.join(converted_arguments)
667 call_template = '$FACTORY_NAME($FACTORY_PARAMS)'
668 call_emitter.Emit(
669 call_template,
670 FACTORY_NAME=qualified_name,
671 FACTORY_PARAMS=args)
672 self.EmitStaticFactoryOverload(constructor_info, name,
673 arguments, constructor_emitter)
674
675 def IsOptional(signature_index, argument):
676 return self.IsConstructorArgumentOptional(argument)
677
678 entry_declaration = emitter.Format(
679 '$(METADATA)$FACTORY_KEYWORD $CTOR($PARAMS)',
680 FACTORY_KEYWORD=('factory' if not custom_factory_ctr else
681 'static %s' % constructor_full_name),
682 CTOR=(('' if not custom_factory_ctr else '_factory') +
683 constructor_full_name),
684 METADATA=metadata,
685 PARAMS=constructor_info.ParametersAsDeclaration(InputType))
686
687 overload_declaration = entry_declaration
688
689 self._GenerateOverloadDispatcher(constructor_info,
690 constructor_info.idl_args, False,
691 overload_declaration, GenerateCall,
692 IsOptional, target_emitter)
693
694 def _AddFutureifiedOperation(self, info, html_name):
695 """Given a API function that uses callbacks, convert it to using Futures.
696
697 This conversion assumes the success callback is always provided before the
698 error callback (and so far in the DOM API, this is the case)."""
699 callback_info = GetCallbackInfo(
700 self._database.GetInterface(info.callback_args[0].type_id))
701
702 # Generated private members never have named arguments.
703 ignore_named_parameters = True if html_name.startswith('_') else False
704
705 # If more than one callback then the second argument is the error callback.
706 # Some error callbacks have 2 args (e.g., executeSql) where the second arg
707 # is the error - this is the argument we want.
708 error_callback = ""
709 if len(info.callback_args) > 1:
710 error_callback_info = GetCallbackInfo(
711 self._database.GetInterface(info.callback_args[1].type_id))
712 error_callbackNames = []
713 for paramInfo in error_callback_info.param_infos:
714 error_callbackNames.append(paramInfo.name)
715 errorCallbackVariables = ", ".join(error_callbackNames)
716 errorName = error_callback_info.param_infos[-1].name
717 error_callback = (
718 ',\n %s(%s) { completer.completeError(%s); }' % (
719 ('%s : ' % info.callback_args[1].name
720 if info.requires_named_arguments and
721 info.callback_args[1].is_optional and
722 not (ignore_named_parameters) else ''),
723 errorCallbackVariables, errorName))
724
725 extensions = GetDDC_Extension(self._interface, info.declared_name)
726 if extensions:
727 ddc_extensions = "\n".join(extensions)
728 else:
729 ddc_extensions = ''
730
731 # Some callbacks have more than one parameters. If so use all of
732 # those parameters. However, if more than one argument use the
733 # type of the last argument to be returned e.g., executeSql the callback
734 # is (transaction, resultSet) and only the resultSet is returned SqlResultSet.
735 callbackArgsLen = len(callback_info.param_infos)
736 future_generic = ''
737 callbackVariables = ''
738 completerVariable = ''
739 if callbackArgsLen == 1:
740 callbackVariables = 'value'
741 completerVariable = callbackVariables
742 if callback_info.param_infos[0].type_id:
743 future_generic = '<%s>' % self._DartType(
744 callback_info.param_infos[0].type_id)
745 elif callbackArgsLen > 1:
746 callbackNames = []
747 for paramInfo in callback_info.param_infos:
748 callbackNames.append(paramInfo.name)
749 callbackVariables = ",".join(callbackNames)
750 completerVariable = callbackNames[-1]
751 future_generic = '<%s>' % self._DartType(
752 callback_info.param_infos[-1].type_id)
753
754 param_list = info.ParametersAsArgumentList(None,
755 ignore_named_parameters)
756 dictionary_argument = info.dictionaryArgumentName()
757
758 convert_map = ''
759 if dictionary_argument is not None:
760 mapArg = dictionary_argument[0]
761 tempVariable = '%s_dict' % mapArg
762 mapArgOptional = dictionary_argument[1]
763
764 if not (extensions):
765 if not (param_list.endswith(', mapArg') or
766 param_list.endswith(', options') or
767 param_list == mapArg):
768 print(
769 "ERROR: %s.%s - Last parameter or only parameter %s is not of type Map"
770 % (self._interface.id, html_name, mapArg))
771 param_list = '%s_dict' % param_list
772
773 if mapArgOptional:
774 convert_map = ' var %s = null;\n'\
775 ' if (%s != null) {\n'\
776 ' %s = convertDartToNative_Dictionary(%s);\n'\
777 ' }\n' % (tempVariable, mapArg, tempVariable, mapArg)
778 else:
779 convert_map = ' var %s = convertDartToNative_Dictionary(%s);\n' % (
780 tempVariable, mapArg)
781
782 metadata = ''
783 if '_RenamingAnnotation' in dir(self):
784 metadata = (
785 self._RenamingAnnotation(info.declared_name, html_name) +
786 self._Metadata(info.type_name, info.declared_name, None,
787 info.type_nullable))
788 self._members_emitter.Emit(
789 '\n'
790 ' $METADATA$MODIFIERS$TYPE$FUTURE_GENERIC $NAME($PARAMS) {\n'
791 ' $CONVERT_DICTIONARY'
792 ' var completer = new Completer$(FUTURE_GENERIC)();\n'
793 ' $ORIGINAL_FUNCTION($PARAMS_LIST\n'
794 ' $NAMED_PARAM($VARIABLE_NAME) { '
795 '$DDC_EXTENSION\n'
796 'completer.complete($COMPLETER_NAME); }'
797 '$ERROR_CALLBACK);\n'
798 ' return completer.future;\n'
799 ' }\n',
800 METADATA=metadata,
801 MODIFIERS='static ' if info.IsStatic() else '',
802 TYPE=self.SecureOutputType(info.type_name,
803 nullable=info.type_nullable),
804 NAME=html_name[1:],
805 PARAMS=info.
806 ParametersAsDeclaration(self._NarrowInputType if '_NarrowInputType'
807 in dir(self) else self._DartType),
808 CONVERT_DICTIONARY=convert_map,
809 PARAMS_LIST='' if param_list == '' else param_list + ',',
810 NAMED_PARAM=('%s : ' % info.callback_args[0].name
811 if info.requires_named_arguments and
812 info.callback_args[0].is_optional and
813 not (ignore_named_parameters) else ''),
814 VARIABLE_NAME=callbackVariables,
815 COMPLETER_NAME=completerVariable,
816 DDC_EXTENSION=ddc_extensions,
817 ERROR_CALLBACK=error_callback,
818 FUTURE_GENERIC=future_generic,
819 ORIGINAL_FUNCTION=html_name)
820
821 def EmitHelpers(self, base_class, members_emitter):
822 if (not self._members_emitter) and (not members_emitter):
823 return
824
825 if self._interface.id not in custom_html_constructors:
826 target_emitter = members_emitter if members_emitter else \
827 self._members_emitter
828 target_emitter.Emit(
829 ' // To suppress missing implicit constructor warnings.\n'
830 ' factory $CLASSNAME._() { '
831 'throw new UnsupportedError("Not supported"); }\n',
832 CLASSNAME=self._interface_type_info.implementation_name())
833
834 def DeclareAttribute(self, attribute, attr_name, read_only):
835 """ Declares an attribute but does not include the code to invoke it.
836 """
837 if read_only:
838 # HACK(terry): Element is not abstract for Dartium so isContentEditable
839 # must have a body see impl_Element.darttemplate
840 if (self._interface.id == 'Element' and
841 attr_name == 'isContentEditable' and self._dart_js_interop):
842 return
843 else:
844 template = '\n $TYPE get $NAME;\n'
845 else:
846 template = '\n $TYPE get $NAME native;\n' \
847 '\n set $NAME($TYPE value) native;\n'
848
849 # Nullability is determined by attribute compatibility.
850 is_compat = self._mdn_reader.is_compatible(attribute)
851 nullable = attribute.type.nullable or not is_compat
852
853 self._members_emitter.Emit(template,
854 NAME=attr_name,
855 TYPE=self.SecureOutputType(
856 attribute.type.id, nullable=nullable))
857
858 def DeclareOperation(self, operation, return_type_name, method_name):
859 """ Declares an operation but does not include the code to invoke it.
860 Arguments:
861 operation - The operation to be declared.
862 return_type_name - The name of the return type.
863 method_name - The name of the method.
864 """
865 # HACK(terry): Element is not abstract for Dartium so click
866 # must have a body see impl_Element.darttemplate
867 if (self._interface.id == 'Element' and method_name == 'click' and
868 self._dart_js_interop):
869 return
870 else:
871 template = '\n $TYPE $NAME($PARAMS);\n'
872
873 self._members_emitter.Emit(
874 template,
875 TYPE=return_type_name,
876 NAME=method_name,
877 PARAMS=operation.ParametersAsDeclaration(self._DartType))
878
879 def EmitListMixin(self, element_name, nullable):
880 # TODO(sra): Use separate mixins for mutable implementations of List<T>.
881 # TODO(sra): Use separate mixins for typed array implementations of List<T>.
882 template_file = 'immutable_list_mixin.darttemplate'
883 has_length = False
884 has_length_setter = False
885
886 def _HasExplicitIndexedGetter(self):
887 return any(op.id == 'getItem' for op in self._interface.operations)
888
889 def _HasCustomIndexedGetter(self):
890 return 'CustomIndexedGetter' in self._interface.ext_attrs
891
892 def _HasNativeIndexedGetter(self):
893 return not (_HasCustomIndexedGetter(self) or
894 _HasExplicitIndexedGetter(self))
895
896 if _HasExplicitIndexedGetter(self):
897 getter_name = 'getItem'
898 else:
899 getter_name = '_nativeIndexedGetter'
900
901 for attr in self._interface.attributes:
902 if attr.id == 'length':
903 has_length = True
904 has_length_setter = not attr.is_read_only
905
906 has_num_items = any(
907 attr.id == 'numberOfItems' for attr in self._interface.attributes)
908
909 template = self._template_loader.Load(
910 template_file, {
911 'DEFINE_LENGTH_AS_NUM_ITEMS':
912 not has_length and has_num_items,
913 'DEFINE_LENGTH_SETTER':
914 not has_length_setter,
915 'USE_NATIVE_INDEXED_GETTER':
916 _HasNativeIndexedGetter(self) or
917 _HasExplicitIndexedGetter(self),
918 })
919 if nullable:
920 element_js = element_name + "|Null"
921 element_name += '?'
922 else:
923 element_js = element_name
924 self._members_emitter.Emit(
925 template, E=element_name, EJS=element_js, GETTER=getter_name)
926
928 type_name,
929 is_dart_type=False,
930 can_narrow_type=False,
931 nullable=False):
932 """ Converts the type name to the secure type name for return types.
933 Arguments:
934 can_narrow_type - True if the output type can be narrowed further than
935 what would be accepted for input, used to narrow num APIs down to double
936 or int.
937 """
938 if is_dart_type:
939 dart_name = type_name
940 else:
941 type_info = self._TypeInfo(type_name)
942 dart_name = type_info.dart_type()
943 if can_narrow_type and dart_name == 'num':
944 dart_name = type_info.native_type()
945
946 # We only need to secure Window. Only local History and Location are
947 # returned in generated code.
948 assert (dart_name != 'HistoryBase' and dart_name != 'LocationBase')
949 if dart_name == 'Window':
950 dart_name = _secure_base_types[dart_name]
951 if type_name == 'any':
952 dart_name = 'Object'
953 if nullable and dart_name != 'dynamic':
954 dart_name = dart_name + '?'
955 return dart_name
956
957 def SecureBaseName(self, type_name):
958 if type_name in _secure_base_types:
959 return _secure_base_types[type_name]
960
961 def is_DOM_type(self, type_name):
962 try:
963 self._type_registry.TypeInfo(type_name)
964 return True
965 except RuntimeError:
966 return False
967
968 def _NarrowToImplementationType(self, type_name):
969 return self._type_registry.TypeInfo(type_name).narrow_dart_type()
970
971 def _NarrowInputType(self, type_name):
972 return self._NarrowToImplementationType(type_name)
973
974 def _DartType(self, type_name):
975 return self._type_registry.DartType(type_name)
976
977 def _TypeInfo(self, type_name):
978 return self._type_registry.TypeInfo(type_name)
979
980 def _CallbackConvert(self, argType, info):
981 if self._database.HasInterface(argType):
982 interface = self._database.GetInterface(argType)
983 if "Callback" in interface.ext_attrs:
984 return interface.ext_attrs['Callback']
985 return None
986
987 def _ConvertArgumentTypes(self, stmts_emitter, arguments, argument_count,
988 info):
989 temp_version = [0]
990 converted_arguments = []
991 target_parameters = []
992 calling_parameters = []
993 for position, arg in enumerate(arguments[:argument_count]):
994 callBackInfo = self._CallbackConvert(
995 arg.type.id, info) # Returns callback arity (# of parameters)
996 if callBackInfo is None:
997 conversion = self._InputConversion(arg.type.id,
998 info.declared_name)
999 else:
1000 conversion = self._InputConversion('Callback',
1001 info.declared_name)
1002
1003 param_name = arguments[position].id
1004 if conversion:
1005 temp_version[0] += 1
1006 temp_name = '%s_%s' % (param_name, temp_version[0])
1007 temp_type = conversion.output_type
1008 null_assert_needed = info.param_infos[position].is_nullable \
1009 and not conversion.nullable_input
1010 stmts_emitter.Emit(
1011 '$(INDENT)$TYPE $NAME = $CONVERT($ARG$NULLASSERT);\n'
1012 if callBackInfo is None else
1013 '$(INDENT)$TYPE $NAME = $CONVERT($ARG$NULLASSERT, $ARITY);\n',
1014 TYPE=TypeOrVar(temp_type),
1015 NAME=temp_name,
1016 CONVERT=conversion.function_name,
1017 ARG=info.param_infos[position].name,
1018 NULLASSERT='!' if null_assert_needed else '',
1019 ARITY=callBackInfo)
1020 converted_arguments.append(temp_name)
1021 param_type = temp_type
1022 verified_type = temp_type # verified by assignment in checked mode.
1023 else:
1024 converted_arguments.append(info.param_infos[position].name)
1025 if self._database.HasTypeDef(arg.type.id):
1026 param_type = 'dynamic'
1027 else:
1028 param_type = self._NarrowInputType(arg.type.id)
1029 # Verified by argument checking on entry to the dispatcher.
1030
1031 verified_type = self._InputType(
1032 info.param_infos[position].type_id, info)
1033 # The native method does not need an argument type if we know the type.
1034 # But we do need the native methods to have correct function types, so
1035 # be conservative.
1036 if param_type == verified_type:
1037 if param_type in [
1038 'String', 'num', 'int', 'double', 'bool',
1039 'Object'
1040 ]:
1041 param_type = 'dynamic'
1042 arg_is_nullable = arg.type.nullable
1043 # If the parameter is either nullable or optional with no non-null
1044 # default value, it is nullable.
1045 if (info.param_infos[position].is_optional and
1046 (info.param_infos[position].default_value_is_null == True or
1047 info.param_infos[position].default_value == None)
1048 ) or info.param_infos[position].is_nullable:
1049 arg_is_nullable = True
1050 target_parameters.append(
1051 '%s%s' % (TypeOrNothing(param_type, nullable=arg_is_nullable),
1052 param_name))
1053 calling_parameters.append(',%s ' % param_name)
1054
1055 return target_parameters, converted_arguments, calling_parameters
1056
1057 def _InputType(self, type_name, info):
1058 conversion = self._InputConversion(type_name, info.declared_name)
1059 if conversion:
1060 return conversion.input_type
1061 else:
1062 # If typedef it's a union return dynamic.
1063 if self._database.HasTypeDef(type_name):
1064 return 'dynamic'
1065 else:
1066 return self._NarrowInputType(
1067 type_name) if type_name else 'dynamic'
static bool is_compatible(const GrSurfaceCharacterization &gsc, const GrBackendTexture &backendTex)
GLenum type
def _GenerateOverloadDispatcher(self, info, signatures, is_void, declaration, generate_call, is_optional, emitter, can_omit_type_check=lambda type, False pos)
def DeclareAttribute(self, attribute, attr_name, read_only)
def AddMembers(self, interface, declare_only=False, dart_js_interop=False)
def _RemoveShadowingOperationsWithSameSignature(self, operationsByName, interface)
def SecureOutputType(self, type_name, is_dart_type=False, can_narrow_type=False, nullable=False)
def DeclareOperation(self, operation, return_type_name, method_name)
def _GetStringRepresentation(self, interface, operation)
def __init__(self, interface, options, dart_use_blink, logger)
def EmitListMixin(self, element_name, nullable)
def _EnsureNoMultipleTypeSignatures(self, interface, operation, operations_by_name)
def AddAttribute(self, attribute, declare_only=False)
def EmitHelpers(self, base_class, members_emitter)
def AddConstructors(self, constructors, factory_name, factory_constructor_name, constructor_emitter)
def _ConvertArgumentTypes(self, stmts_emitter, arguments, argument_count, info)
def AddOperation(self, info, declare_only=False, dart_js_interop=False)
def _AddConstructor(self, constructor_info, factory_name, factory_constructor_name, constructor_emitter)
def EmitEventGetter(self, events_class_name)
def _AddDesiredOverloadedOperations(self, potential_added_operations, interface, original_operations_by_name)
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition: editor.cpp:211
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
def print(*args, **kwargs)
Definition: run_tests.py:49
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741