Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / scripts / unstable / v8_interface.py
1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
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
12 # distribution.
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.
16 #
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.
28
29 """Generate template values for an interface.
30
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
36 """
37
38 import v8_attributes
39 from v8_globals import includes
40 import v8_methods
41 import v8_types
42 from v8_types import inherits_interface, is_interface_type
43 import v8_utilities
44 from v8_utilities import capitalize, conditional_string, cpp_name, has_extended_attribute_value, runtime_enabled_function_name
45
46
47 INTERFACE_H_INCLUDES = set([
48     'bindings/v8/V8Binding.h',
49     'bindings/v8/V8DOMWrapper.h',
50     'bindings/v8/WrapperTypeInfo.h',
51     'heap/Handle.h',
52 ])
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
62     'wtf/RefPtr.h',
63 ])
64
65
66 def generate_interface(interface):
67     includes.clear()
68     includes.update(INTERFACE_CPP_INCLUDES)
69     header_includes = INTERFACE_H_INCLUDES
70
71     parent_interface = interface.parent
72     if parent_interface:
73         header_includes.update(v8_types.includes_for_type(parent_interface))
74     extended_attributes = interface.extended_attributes
75
76     is_audio_buffer = inherits_interface(interface.name, 'AudioBuffer')
77     if is_audio_buffer:
78         includes.add('modules/webaudio/AudioBuffer.h')
79
80     is_document = inherits_interface(interface.name, 'Document')
81     if is_document:
82         includes.update(['bindings/v8/ScriptController.h',
83                          'bindings/v8/V8WindowShell.h',
84                          'core/frame/Frame.h'])
85
86     # [CheckSecurity]
87     is_check_security = 'CheckSecurity' in extended_attributes
88     if is_check_security:
89         includes.add('bindings/v8/BindingSecurity.h')
90
91     # [MeasureAs]
92     is_measure_as = 'MeasureAs' in extended_attributes
93     if is_measure_as:
94         includes.add('core/frame/UseCounter.h')
95
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'])
101
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'])
110
111     # [SpecialWrapFor]
112     if 'SpecialWrapFor' in extended_attributes:
113         special_wrap_for = extended_attributes['SpecialWrapFor'].split('|')
114     else:
115         special_wrap_for = []
116     for special_wrap_interface in special_wrap_for:
117         v8_types.add_includes_for_type(special_wrap_interface)
118
119     # [WillBeGarbageCollected]
120     is_will_be_garbage_collected = 'WillBeGarbageCollected' in extended_attributes
121
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),
154     }
155
156     # Constructors
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)
164
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]
170
171     # [EventConstructor]
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')
179
180     # [NamedConstructor]
181     named_constructor = generate_named_constructor(interface)
182
183     if (constructors or custom_constructors or has_event_constructor or
184         named_constructor):
185         includes.add('bindings/v8/V8ObjectConstructor.h')
186
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,
192         'interface_length':
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,
200     })
201
202     # Constants
203     template_contents.update({
204         'constants': [generate_constant(constant) for constant in interface.constants],
205         'do_not_check_constants': 'DoNotCheckConstants' in extended_attributes,
206     })
207
208     # 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),
223     })
224
225     # Methods
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))
236
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),
243         'methods': methods,
244     })
245
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),
254     })
255
256     return template_contents
257
258
259 # [DeprecateAs], [Reflect], [RuntimeEnabled]
260 def generate_constant(constant):
261     # (Blink-only) string literals are unquoted in tokenizer, must be re-quoted
262     # in C++.
263     if constant.idl_type == 'DOMString':
264         value = '"%s"' % constant.value
265     else:
266         value = constant.value
267
268     extended_attributes = constant.extended_attributes
269     return {
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),
275         'value': value,
276     }
277
278
279 ################################################################################
280 # Overloads
281 ################################################################################
282
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)
286
287
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
292     method_counts = {}
293     for method in methods:
294         if method['is_static'] != is_static:
295             continue
296         name = method['name']
297         method_counts.setdefault(name, 0)
298         method_counts[name] += 1
299
300     # Filter to only methods that are actually overloaded
301     overloaded_method_counts = dict((name, count)
302                                     for name, count in method_counts.iteritems()
303                                     if count > 1)
304
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):
312             continue
313         # Overload index includes self, so first append, then compute index
314         method_overloads.setdefault(name, []).append(method)
315         method.update({
316             'overload_index': len(method_overloads[name]),
317             'overload_resolution_expression': overload_resolution_expression(method),
318         })
319
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):
325             continue
326         name = method['name']
327         if method['overload_index'] != overloaded_method_counts[name]:
328             continue
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,
337             'name': name,
338         }
339
340
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
347     #
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).
354     #
355     # Properly:
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)
373
374
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)
382
383
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()'
394         return None
395
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])
412         return 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,
422                                       type_check])
423         return type_check
424     return None
425
426
427 ################################################################################
428 # Constructors
429 ################################################################################
430
431 # [Constructor]
432 def generate_constructor(interface, constructor):
433     return {
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),
447     }
448
449
450 def constructor_argument_list(interface, constructor):
451     arguments = []
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')
458
459     arguments.extend([argument.name for argument in constructor.arguments])
460
461     # [RaisesException=Constructor]
462     if interface.extended_attributes.get('RaisesException') == 'Constructor':
463         arguments.append('exceptionState')
464
465     return arguments
466
467
468 def constructor_argument(argument, index):
469     return {
470         'has_default': 'Default' in argument.extended_attributes,
471         'idl_type': argument.idl_type,
472         'index': index,
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),
479     }
480
481
482 def generate_constructor_overloads(constructors):
483     if len(constructors) <= 1:
484         return
485     for overload_index, constructor in enumerate(constructors):
486         constructor.update({
487             'overload_index': overload_index + 1,
488             'overload_resolution_expression':
489                 overload_resolution_expression(constructor),
490         })
491
492
493 # [NamedConstructor]
494 def generate_named_constructor(interface):
495     extended_attributes = interface.extended_attributes
496     if 'NamedConstructor' not in extended_attributes:
497         return None
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']
505     return constructor
506
507
508 def number_of_required_arguments(constructor):
509     return len([argument for argument in constructor.arguments
510                 if not argument.is_optional])
511
512
513 def interface_length(interface, constructors):
514     # Docs: http://heycam.github.io/webidl/#es-interface-call
515     if 'EventConstructor' in interface.extended_attributes:
516         return 1
517     if not constructors:
518         return 0
519     return min(constructor['number_of_required_arguments']
520                for constructor in constructors)
521
522
523 ################################################################################
524 # Special operations (methods)
525 # http://heycam.github.io/webidl/#idl-special-operations
526 ################################################################################
527
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
532                                for i, _ in
533                                enumerate(idl_type.union_member_types))
534         if idl_type == 'DOMString':
535             return 'result.isNull()'
536         if is_interface_type(idl_type):
537             return '!result'
538         return ''
539
540     idl_type = getter.idl_type
541     extended_attributes = getter.extended_attributes
542     is_raises_exception = 'RaisesException' in extended_attributes
543
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]
547     else:
548         release = v8_types.is_interface_type(idl_type)
549
550     # FIXME: make more generic, so can use v8_methods.cpp_value
551     cpp_method_name = 'imp->%s' % cpp_name(getter)
552
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)
558
559     cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments))
560
561     return {
562         'cpp_type': v8_types.cpp_type(idl_type),
563         'cpp_value': cpp_value,
564         'is_custom':
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),
578     }
579
580
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
585     return {
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'),
597     }
598
599
600 def property_deleter(deleter):
601     idl_type = deleter.idl_type
602     if idl_type != 'boolean':
603         raise Exception(
604             'Only deleters with boolean type are allowed, but type is "%s"' %
605             idl_type)
606     extended_attributes = deleter.extended_attributes
607     return {
608         'is_custom': 'Custom' in extended_attributes,
609         'is_raises_exception': 'RaisesException' in extended_attributes,
610         'name': cpp_name(deleter),
611     }
612
613
614 ################################################################################
615 # Indexed properties
616 # http://heycam.github.io/webidl/#idl-indexed-properties
617 ################################################################################
618
619 def indexed_property_getter(interface):
620     try:
621         # Find indexed property getter, if present; has form:
622         # getter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1)
623         getter = next(
624             method
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:
630         return None
631
632     return property_getter(getter, ['index'])
633
634
635 def indexed_property_setter(interface):
636     try:
637         # Find indexed property setter, if present; has form:
638         # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE ARG2)
639         setter = next(
640             method
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:
646         return None
647
648     return property_setter(setter)
649
650
651 def indexed_property_deleter(interface):
652     try:
653         # Find indexed property deleter, if present; has form:
654         # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG)
655         deleter = next(
656             method
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:
662         return None
663
664     return property_deleter(deleter)
665
666
667 ################################################################################
668 # Named properties
669 # http://heycam.github.io/webidl/#idl-named-properties
670 ################################################################################
671
672 def named_property_getter(interface):
673     try:
674         # Find named property getter, if present; has form:
675         # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1)
676         getter = next(
677             method
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:
683         return None
684
685     getter.name = getter.name or 'anonymousNamedGetter'
686     return property_getter(getter, ['propertyName'])
687
688
689 def named_property_setter(interface):
690     try:
691         # Find named property setter, if present; has form:
692         # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2)
693         setter = next(
694             method
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:
700         return None
701
702     return property_setter(setter)
703
704
705 def named_property_deleter(interface):
706     try:
707         # Find named property deleter, if present; has form:
708         # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG)
709         deleter = next(
710             method
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:
716         return None
717
718     return property_deleter(deleter)