1 # Copyright (C) 2013 Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 """Generate template values for an interface.
31 FIXME: Not currently used in build.
32 This is a rewrite of the Perl IDL compiler in Python, but is not complete.
33 Once it is complete, we will switch all IDL files over to Python at once.
34 Until then, please work on the Perl IDL compiler.
35 For details, see bug http://crbug.com/239771
39 from v8_globals import includes
42 from v8_types import inherits_interface, is_interface_type
44 from v8_utilities import capitalize, conditional_string, cpp_name, has_extended_attribute_value, runtime_enabled_function_name
47 INTERFACE_H_INCLUDES = set([
48 'bindings/v8/V8Binding.h',
49 'bindings/v8/V8DOMWrapper.h',
50 'bindings/v8/WrapperTypeInfo.h',
53 INTERFACE_CPP_INCLUDES = set([
54 'RuntimeEnabledFeatures.h',
55 'bindings/v8/ExceptionState.h',
56 'bindings/v8/V8DOMConfiguration.h',
57 'bindings/v8/V8ObjectConstructor.h',
58 'core/dom/ContextFeatures.h',
59 'core/dom/Document.h',
60 'platform/TraceEvent.h',
61 'wtf/GetPtr.h', # FIXME: remove if can eliminate WTF::getPtr
66 def generate_interface(interface):
68 includes.update(INTERFACE_CPP_INCLUDES)
69 header_includes = INTERFACE_H_INCLUDES
71 parent_interface = interface.parent
73 header_includes.update(v8_types.includes_for_type(parent_interface))
74 extended_attributes = interface.extended_attributes
76 is_audio_buffer = inherits_interface(interface.name, 'AudioBuffer')
78 includes.add('modules/webaudio/AudioBuffer.h')
80 is_document = inherits_interface(interface.name, 'Document')
82 includes.update(['bindings/v8/ScriptController.h',
83 'bindings/v8/V8WindowShell.h',
84 'core/frame/Frame.h'])
87 is_check_security = 'CheckSecurity' in extended_attributes
89 includes.add('bindings/v8/BindingSecurity.h')
92 is_measure_as = 'MeasureAs' in extended_attributes
94 includes.add('core/frame/UseCounter.h')
96 # [SetWrapperReferenceFrom]
97 reachable_node_function = extended_attributes.get('SetWrapperReferenceFrom')
98 if reachable_node_function:
99 includes.update(['bindings/v8/V8GCController.h',
100 'core/dom/Element.h'])
102 # [SetWrapperReferenceTo]
103 set_wrapper_reference_to_list = [{
104 'name': argument.name,
105 'idl_type': argument.idl_type,
106 'v8_type': v8_types.v8_type(argument.idl_type),
107 } for argument in extended_attributes.get('SetWrapperReferenceTo', [])]
108 for set_wrapper_reference_to in set_wrapper_reference_to_list:
109 v8_types.add_includes_for_type(set_wrapper_reference_to['idl_type'])
112 if 'SpecialWrapFor' in extended_attributes:
113 special_wrap_for = extended_attributes['SpecialWrapFor'].split('|')
115 special_wrap_for = []
116 for special_wrap_interface in special_wrap_for:
117 v8_types.add_includes_for_type(special_wrap_interface)
119 # [WillBeGarbageCollected]
120 is_will_be_garbage_collected = 'WillBeGarbageCollected' in extended_attributes
122 template_contents = {
123 'conditional_string': conditional_string(interface), # [Conditional]
124 'cpp_class': cpp_name(interface),
125 'has_custom_legacy_call_as_function': has_extended_attribute_value(interface, 'Custom', 'LegacyCallAsFunction'), # [Custom=LegacyCallAsFunction]
126 'has_custom_to_v8': has_extended_attribute_value(interface, 'Custom', 'ToV8'), # [Custom=ToV8]
127 'has_custom_wrap': has_extended_attribute_value(interface, 'Custom', 'Wrap'), # [Custom=Wrap]
128 'has_visit_dom_wrapper': (
129 # [Custom=Wrap], [SetWrapperReferenceFrom]
130 has_extended_attribute_value(interface, 'Custom', 'VisitDOMWrapper') or
131 reachable_node_function or set_wrapper_reference_to_list),
132 'header_includes': header_includes,
133 'interface_name': interface.name,
134 'is_active_dom_object': 'ActiveDOMObject' in extended_attributes, # [ActiveDOMObject]
135 'is_audio_buffer': is_audio_buffer,
136 'is_check_security': is_check_security,
137 'is_dependent_lifetime': 'DependentLifetime' in extended_attributes, # [DependentLifetime]
138 'is_document': is_document,
139 'is_event_target': inherits_interface(interface.name, 'EventTarget'),
140 'is_exception': interface.is_exception,
141 'is_will_be_garbage_collected': is_will_be_garbage_collected,
142 'is_node': inherits_interface(interface.name, 'Node'),
143 'measure_as': v8_utilities.measure_as(interface), # [MeasureAs]
144 'parent_interface': parent_interface,
145 'pass_ref_ptr': 'PassRefPtrWillBeRawPtr'
146 if is_will_be_garbage_collected else 'PassRefPtr',
147 'reachable_node_function': reachable_node_function,
148 'ref_ptr': 'RefPtrWillBeRawPtr'
149 if is_will_be_garbage_collected else 'RefPtr',
150 'runtime_enabled_function': runtime_enabled_function_name(interface), # [RuntimeEnabled]
151 'set_wrapper_reference_to_list': set_wrapper_reference_to_list,
152 'special_wrap_for': special_wrap_for,
153 'v8_class': v8_utilities.v8_class_name(interface),
157 constructors = [generate_constructor(interface, constructor)
158 for constructor in interface.constructors
159 # FIXME: shouldn't put named constructors with constructors
160 # (currently needed for Perl compatibility)
161 # Handle named constructors separately
162 if constructor.name == 'Constructor']
163 generate_constructor_overloads(constructors)
165 # [CustomConstructor]
166 custom_constructors = [{ # Only needed for computing interface length
167 'number_of_required_arguments':
168 number_of_required_arguments(constructor),
169 } for constructor in interface.custom_constructors]
172 has_event_constructor = 'EventConstructor' in extended_attributes
173 any_type_attributes = [attribute for attribute in interface.attributes
174 if attribute.idl_type == 'any']
175 if has_event_constructor:
176 includes.add('bindings/v8/Dictionary.h')
177 if any_type_attributes:
178 includes.add('bindings/v8/SerializedScriptValue.h')
181 named_constructor = generate_named_constructor(interface)
183 if (constructors or custom_constructors or has_event_constructor or
185 includes.add('bindings/v8/V8ObjectConstructor.h')
187 template_contents.update({
188 'any_type_attributes': any_type_attributes,
189 'constructors': constructors,
190 'has_custom_constructor': bool(custom_constructors),
191 'has_event_constructor': has_event_constructor,
193 interface_length(interface, constructors + custom_constructors),
194 'is_constructor_call_with_document': has_extended_attribute_value(
195 interface, 'ConstructorCallWith', 'Document'), # [ConstructorCallWith=Document]
196 'is_constructor_call_with_execution_context': has_extended_attribute_value(
197 interface, 'ConstructorCallWith', 'ExecutionContext'), # [ConstructorCallWith=ExeuctionContext]
198 'is_constructor_raises_exception': extended_attributes.get('RaisesException') == 'Constructor', # [RaisesException=Constructor]
199 'named_constructor': named_constructor,
203 template_contents.update({
204 'constants': [generate_constant(constant) for constant in interface.constants],
205 'do_not_check_constants': 'DoNotCheckConstants' in extended_attributes,
209 attributes = [v8_attributes.generate_attribute(interface, attribute)
210 for attribute in interface.attributes]
211 template_contents.update({
212 'attributes': attributes,
213 'has_accessors': any(attribute['is_expose_js_accessors'] for attribute in attributes),
214 'has_attribute_configuration': any(
215 not (attribute['is_expose_js_accessors'] or
216 attribute['is_static'] or
217 attribute['runtime_enabled_function'] or
218 attribute['per_context_enabled_function'])
219 for attribute in attributes),
220 'has_constructor_attributes': any(attribute['constructor_type'] for attribute in attributes),
221 'has_per_context_enabled_attributes': any(attribute['per_context_enabled_function'] for attribute in attributes),
222 'has_replaceable_attributes': any(attribute['is_replaceable'] for attribute in attributes),
226 methods = [v8_methods.generate_method(interface, method)
227 for method in interface.operations
228 if method.name] # Skip anonymous special operations (methods)
229 generate_overloads(methods)
230 for method in methods:
231 method['do_generate_method_configuration'] = (
232 method['do_not_check_signature'] and
233 not method['per_context_enabled_function'] and
234 # For overloaded methods, only generate one accessor
235 ('overload_index' not in method or method['overload_index'] == 1))
237 template_contents.update({
238 'has_origin_safe_method_setter': any(
239 method['is_check_security_for_frame'] and not method['is_read_only']
240 for method in methods),
241 'has_method_configuration': any(method['do_generate_method_configuration'] for method in methods),
242 'has_per_context_enabled_methods': any(method['per_context_enabled_function'] for method in methods),
246 template_contents.update({
247 'indexed_property_getter': indexed_property_getter(interface),
248 'indexed_property_setter': indexed_property_setter(interface),
249 'indexed_property_deleter': indexed_property_deleter(interface),
250 'is_override_builtins': 'OverrideBuiltins' in extended_attributes,
251 'named_property_getter': named_property_getter(interface),
252 'named_property_setter': named_property_setter(interface),
253 'named_property_deleter': named_property_deleter(interface),
256 return template_contents
259 # [DeprecateAs], [Reflect], [RuntimeEnabled]
260 def generate_constant(constant):
261 # (Blink-only) string literals are unquoted in tokenizer, must be re-quoted
263 if constant.idl_type == 'DOMString':
264 value = '"%s"' % constant.value
266 value = constant.value
268 extended_attributes = constant.extended_attributes
270 'cpp_class': extended_attributes.get('ImplementedBy'),
271 'name': constant.name,
272 # FIXME: use 'reflected_name' as correct 'name'
273 'reflected_name': extended_attributes.get('Reflect', constant.name),
274 'runtime_enabled_function': runtime_enabled_function_name(constant),
279 ################################################################################
281 ################################################################################
283 def generate_overloads(methods):
284 generate_overloads_by_type(methods, is_static=False) # Regular methods
285 generate_overloads_by_type(methods, is_static=True)
288 def generate_overloads_by_type(methods, is_static):
289 # Generates |overloads| template values and modifies |methods| in place;
290 # |is_static| flag used (instead of partitioning list in 2) because need to
291 # iterate over original list of methods to modify in place
293 for method in methods:
294 if method['is_static'] != is_static:
296 name = method['name']
297 method_counts.setdefault(name, 0)
298 method_counts[name] += 1
300 # Filter to only methods that are actually overloaded
301 overloaded_method_counts = dict((name, count)
302 for name, count in method_counts.iteritems()
305 # Add overload information only to overloaded methods, so template code can
306 # easily verify if a function is overloaded
307 method_overloads = {}
308 for method in methods:
309 name = method['name']
310 if (method['is_static'] != is_static or
311 name not in overloaded_method_counts):
313 # Overload index includes self, so first append, then compute index
314 method_overloads.setdefault(name, []).append(method)
316 'overload_index': len(method_overloads[name]),
317 'overload_resolution_expression': overload_resolution_expression(method),
320 # Resolution function is generated after last overloaded function;
321 # package necessary information into |method.overloads| for that method.
322 for method in methods:
323 if (method['is_static'] != is_static or
324 'overload_index' not in method):
326 name = method['name']
327 if method['overload_index'] != overloaded_method_counts[name]:
329 overloads = method_overloads[name]
330 minimum_number_of_required_arguments = min(
331 overload['number_of_required_arguments']
332 for overload in overloads)
333 method['overloads'] = {
334 'has_exception_state': bool(minimum_number_of_required_arguments),
335 'methods': overloads,
336 'minimum_number_of_required_arguments': minimum_number_of_required_arguments,
341 def overload_resolution_expression(method):
342 # Expression is an OR of ANDs: each term in the OR corresponds to a
343 # possible argument count for a given method, with type checks.
344 # FIXME: Blink's overload resolution algorithm is incorrect, per:
345 # Implement WebIDL overload resolution algorithm.
346 # https://code.google.com/p/chromium/issues/detail?id=293561
348 # Currently if distinguishing non-primitive type from primitive type,
349 # (e.g., sequence<DOMString> from DOMString or Dictionary from double)
350 # the method with a non-primitive type argument must appear *first* in the
351 # IDL file, since we're not adding a check to primitive types.
352 # FIXME: Once fixed, check IDLs, as usually want methods with primitive
353 # types to appear first (style-wise).
356 # 1. Compute effective overload set.
357 # 2. First check type list length.
358 # 3. If multiple entries for given length, compute distinguishing argument
359 # index and have check for that type.
360 arguments = method['arguments']
361 overload_checks = [overload_check_expression(method, index)
362 # check *omitting* optional arguments at |index| and up:
363 # index 0 => argument_count 0 (no arguments)
364 # index 1 => argument_count 1 (index 0 argument only)
365 for index, argument in enumerate(arguments)
366 if argument['is_optional']]
367 # FIXME: this is wrong if a method has optional arguments and a variadic
368 # one, though there are not yet any examples of this
369 if not method['is_variadic']:
370 # Includes all optional arguments (len = last index + 1)
371 overload_checks.append(overload_check_expression(method, len(arguments)))
372 return ' || '.join('(%s)' % check for check in overload_checks)
375 def overload_check_expression(method, argument_count):
376 overload_checks = ['info.Length() == %s' % argument_count]
377 arguments = method['arguments'][:argument_count]
378 overload_checks.extend(overload_check_argument(index, argument)
379 for index, argument in
380 enumerate(arguments))
381 return ' && '.join('(%s)' % check for check in overload_checks if check)
384 def overload_check_argument(index, argument):
385 def null_or_optional_check():
386 # If undefined is passed for an optional argument, the argument should
387 # be treated as missing; otherwise undefined is not allowed.
388 if argument['is_nullable']:
389 if argument['is_optional']:
390 return 'isUndefinedOrNull(%s)'
391 return '%s->IsNull()'
392 if argument['is_optional']:
393 return '%s->IsUndefined()'
396 cpp_value = 'info[%s]' % index
397 idl_type = argument['idl_type']
398 # FIXME: proper type checking, sharing code with attributes and methods
399 if idl_type == 'DOMString' and argument['is_strict_type_checking']:
400 return ' || '.join(['isUndefinedOrNull(%s)' % cpp_value,
401 '%s->IsString()' % cpp_value,
402 '%s->IsObject()' % cpp_value])
403 if v8_types.array_or_sequence_type(idl_type):
404 return '%s->IsArray()' % cpp_value
405 if v8_types.is_callback_interface(idl_type):
406 return ' || '.join(['%s->IsNull()' % cpp_value,
407 '%s->IsFunction()' % cpp_value])
408 if v8_types.is_wrapper_type(idl_type):
409 type_check = 'V8{idl_type}::hasInstance({cpp_value}, info.GetIsolate())'.format(idl_type=idl_type, cpp_value=cpp_value)
410 if argument['is_nullable']:
411 type_check = ' || '.join(['%s->IsNull()' % cpp_value, type_check])
413 if is_interface_type(idl_type):
414 # Non-wrapper types are just objects: we don't distinguish type
415 # We only allow undefined for non-wrapper types (notably Dictionary),
416 # as we need it for optional Dictionary arguments, but we don't want to
417 # change behavior of existing bindings for other types.
418 type_check = '%s->IsObject()' % cpp_value
419 added_check_template = null_or_optional_check()
420 if added_check_template:
421 type_check = ' || '.join([added_check_template % cpp_value,
427 ################################################################################
429 ################################################################################
432 def generate_constructor(interface, constructor):
434 'argument_list': constructor_argument_list(interface, constructor),
435 'arguments': [constructor_argument(argument, index)
436 for index, argument in enumerate(constructor.arguments)],
437 'has_exception_state':
438 # [RaisesException=Constructor]
439 interface.extended_attributes.get('RaisesException') == 'Constructor' or
440 any(argument for argument in constructor.arguments
441 if argument.idl_type == 'SerializedScriptValue' or
442 v8_types.is_integer_type(argument.idl_type)),
443 'is_constructor': True,
444 'is_variadic': False, # Required for overload resolution
445 'number_of_required_arguments':
446 number_of_required_arguments(constructor),
450 def constructor_argument_list(interface, constructor):
452 # [ConstructorCallWith=ExecutionContext]
453 if has_extended_attribute_value(interface, 'ConstructorCallWith', 'ExecutionContext'):
454 arguments.append('context')
455 # [ConstructorCallWith=Document]
456 if has_extended_attribute_value(interface, 'ConstructorCallWith', 'Document'):
457 arguments.append('document')
459 arguments.extend([argument.name for argument in constructor.arguments])
461 # [RaisesException=Constructor]
462 if interface.extended_attributes.get('RaisesException') == 'Constructor':
463 arguments.append('exceptionState')
468 def constructor_argument(argument, index):
470 'has_default': 'Default' in argument.extended_attributes,
471 'idl_type': argument.idl_type,
473 'is_nullable': False, # Required for overload resolution
474 'is_optional': argument.is_optional,
475 'is_strict_type_checking': False, # Required for overload resolution
476 'name': argument.name,
477 'v8_value_to_local_cpp_value':
478 v8_methods.v8_value_to_local_cpp_value(argument, index),
482 def generate_constructor_overloads(constructors):
483 if len(constructors) <= 1:
485 for overload_index, constructor in enumerate(constructors):
487 'overload_index': overload_index + 1,
488 'overload_resolution_expression':
489 overload_resolution_expression(constructor),
494 def generate_named_constructor(interface):
495 extended_attributes = interface.extended_attributes
496 if 'NamedConstructor' not in extended_attributes:
498 # FIXME: parser should return named constructor separately;
499 # included in constructors (and only name stored in extended attribute)
500 # for Perl compatibility
501 idl_constructor = interface.constructors[0]
502 constructor = generate_constructor(interface, idl_constructor)
503 constructor['argument_list'].insert(0, '*document')
504 constructor['name'] = extended_attributes['NamedConstructor']
508 def number_of_required_arguments(constructor):
509 return len([argument for argument in constructor.arguments
510 if not argument.is_optional])
513 def interface_length(interface, constructors):
514 # Docs: http://heycam.github.io/webidl/#es-interface-call
515 if 'EventConstructor' in interface.extended_attributes:
519 return min(constructor['number_of_required_arguments']
520 for constructor in constructors)
523 ################################################################################
524 # Special operations (methods)
525 # http://heycam.github.io/webidl/#idl-special-operations
526 ################################################################################
528 def property_getter(getter, cpp_arguments):
529 def is_null_expression(idl_type):
530 if v8_types.is_union_type(idl_type):
531 return ' && '.join('!result%sEnabled' % i
533 enumerate(idl_type.union_member_types))
534 if idl_type == 'DOMString':
535 return 'result.isNull()'
536 if is_interface_type(idl_type):
540 idl_type = getter.idl_type
541 extended_attributes = getter.extended_attributes
542 is_raises_exception = 'RaisesException' in extended_attributes
544 if v8_types.is_union_type(idl_type):
545 release = [v8_types.is_interface_type(union_member_type)
546 for union_member_type in idl_type.union_member_types]
548 release = v8_types.is_interface_type(idl_type)
550 # FIXME: make more generic, so can use v8_methods.cpp_value
551 cpp_method_name = 'imp->%s' % cpp_name(getter)
553 if is_raises_exception:
554 cpp_arguments.append('exceptionState')
555 this_union_arguments = v8_methods.union_arguments(idl_type)
556 if this_union_arguments:
557 cpp_arguments.extend(this_union_arguments)
559 cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments))
562 'cpp_type': v8_types.cpp_type(idl_type),
563 'cpp_value': cpp_value,
565 'Custom' in extended_attributes and
566 (not extended_attributes['Custom'] or
567 has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')),
568 'is_custom_property_enumerator': has_extended_attribute_value(
569 getter, 'Custom', 'PropertyEnumerator'),
570 'is_custom_property_query': has_extended_attribute_value(
571 getter, 'Custom', 'PropertyQuery'),
572 'is_enumerable': 'NotEnumerable' not in extended_attributes,
573 'is_null_expression': is_null_expression(idl_type),
574 'is_raises_exception': is_raises_exception,
575 'name': cpp_name(getter),
576 'union_arguments': v8_methods.union_arguments(idl_type),
577 'v8_set_return_value': v8_types.v8_set_return_value(idl_type, 'result', extended_attributes=extended_attributes, script_wrappable='imp', release=release),
581 def property_setter(setter):
582 idl_type = setter.arguments[1].idl_type
583 extended_attributes = setter.extended_attributes
584 is_raises_exception = 'RaisesException' in extended_attributes
586 'has_strict_type_checking':
587 'StrictTypeChecking' in extended_attributes and
588 v8_types.is_wrapper_type(idl_type),
589 'idl_type': idl_type,
590 'is_custom': 'Custom' in extended_attributes,
591 'has_exception_state': is_raises_exception or
592 v8_types.is_integer_type(idl_type),
593 'is_raises_exception': is_raises_exception,
594 'name': cpp_name(setter),
595 'v8_value_to_local_cpp_value': v8_types.v8_value_to_local_cpp_value(
596 idl_type, extended_attributes, 'jsValue', 'propertyValue'),
600 def property_deleter(deleter):
601 idl_type = deleter.idl_type
602 if idl_type != 'boolean':
604 'Only deleters with boolean type are allowed, but type is "%s"' %
606 extended_attributes = deleter.extended_attributes
608 'is_custom': 'Custom' in extended_attributes,
609 'is_raises_exception': 'RaisesException' in extended_attributes,
610 'name': cpp_name(deleter),
614 ################################################################################
616 # http://heycam.github.io/webidl/#idl-indexed-properties
617 ################################################################################
619 def indexed_property_getter(interface):
621 # Find indexed property getter, if present; has form:
622 # getter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1)
625 for method in interface.operations
626 if ('getter' in method.specials and
627 len(method.arguments) == 1 and
628 method.arguments[0].idl_type == 'unsigned long'))
629 except StopIteration:
632 return property_getter(getter, ['index'])
635 def indexed_property_setter(interface):
637 # Find indexed property setter, if present; has form:
638 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE ARG2)
641 for method in interface.operations
642 if ('setter' in method.specials and
643 len(method.arguments) == 2 and
644 method.arguments[0].idl_type == 'unsigned long'))
645 except StopIteration:
648 return property_setter(setter)
651 def indexed_property_deleter(interface):
653 # Find indexed property deleter, if present; has form:
654 # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG)
657 for method in interface.operations
658 if ('deleter' in method.specials and
659 len(method.arguments) == 1 and
660 method.arguments[0].idl_type == 'unsigned long'))
661 except StopIteration:
664 return property_deleter(deleter)
667 ################################################################################
669 # http://heycam.github.io/webidl/#idl-named-properties
670 ################################################################################
672 def named_property_getter(interface):
674 # Find named property getter, if present; has form:
675 # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1)
678 for method in interface.operations
679 if ('getter' in method.specials and
680 len(method.arguments) == 1 and
681 method.arguments[0].idl_type == 'DOMString'))
682 except StopIteration:
685 getter.name = getter.name or 'anonymousNamedGetter'
686 return property_getter(getter, ['propertyName'])
689 def named_property_setter(interface):
691 # Find named property setter, if present; has form:
692 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2)
695 for method in interface.operations
696 if ('setter' in method.specials and
697 len(method.arguments) == 2 and
698 method.arguments[0].idl_type == 'DOMString'))
699 except StopIteration:
702 return property_setter(setter)
705 def named_property_deleter(interface):
707 # Find named property deleter, if present; has form:
708 # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG)
711 for method in interface.operations
712 if ('deleter' in method.specials and
713 len(method.arguments) == 1 and
714 method.arguments[0].idl_type == 'DOMString'))
715 except StopIteration:
718 return property_deleter(deleter)