OLD | NEW |
| (Empty) |
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 = frozenset([ | |
48 'bindings/v8/V8Binding.h', | |
49 'bindings/v8/V8DOMWrapper.h', | |
50 'bindings/v8/WrapperTypeInfo.h', | |
51 'heap/Handle.h', | |
52 ]) | |
53 INTERFACE_CPP_INCLUDES = frozenset([ | |
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 = set(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/LocalFrame.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 reachable_node_reference_function = extended_attributes.get('SetWrapperRefer
enceFromReference') | |
99 if reachable_node_function or reachable_node_reference_function: | |
100 includes.update(['bindings/v8/V8GCController.h', | |
101 'core/dom/Element.h']) | |
102 | |
103 # [SetWrapperReferenceTo] | |
104 set_wrapper_reference_to_list = [{ | |
105 'name': argument.name, | |
106 # FIXME: properly should be: | |
107 # 'cpp_type': v8_types.cpp_type(argument.idl_type, used_as_argument=True
), | |
108 # (if type is non-wrapper type like NodeFilter, normally RefPtr) | |
109 # Raw pointers faster though, and NodeFilter hacky anyway. | |
110 'cpp_type': v8_types.implemented_as(argument.idl_type) + '*', | |
111 'idl_type': argument.idl_type, | |
112 'v8_type': v8_types.v8_type(argument.idl_type), | |
113 } for argument in extended_attributes.get('SetWrapperReferenceTo', [])] | |
114 for set_wrapper_reference_to in set_wrapper_reference_to_list: | |
115 v8_types.add_includes_for_type(set_wrapper_reference_to['idl_type']) | |
116 | |
117 # [SpecialWrapFor] | |
118 if 'SpecialWrapFor' in extended_attributes: | |
119 special_wrap_for = extended_attributes['SpecialWrapFor'].split('|') | |
120 else: | |
121 special_wrap_for = [] | |
122 for special_wrap_interface in special_wrap_for: | |
123 v8_types.add_includes_for_type(special_wrap_interface) | |
124 | |
125 # [WillBeGarbageCollected] | |
126 is_will_be_garbage_collected = 'WillBeGarbageCollected' in extended_attribut
es | |
127 | |
128 template_contents = { | |
129 'conditional_string': conditional_string(interface), # [Conditional] | |
130 'cpp_class': cpp_name(interface), | |
131 'has_custom_legacy_call_as_function': has_extended_attribute_value(inter
face, 'Custom', 'LegacyCallAsFunction'), # [Custom=LegacyCallAsFunction] | |
132 'has_custom_to_v8': has_extended_attribute_value(interface, 'Custom', 'T
oV8'), # [Custom=ToV8] | |
133 'has_custom_wrap': has_extended_attribute_value(interface, 'Custom', 'Wr
ap'), # [Custom=Wrap] | |
134 'has_visit_dom_wrapper': ( | |
135 # [Custom=Wrap], [SetWrapperReferenceFrom] | |
136 has_extended_attribute_value(interface, 'Custom', 'VisitDOMWrapper')
or | |
137 reachable_node_function or | |
138 reachable_node_reference_function or | |
139 set_wrapper_reference_to_list), | |
140 'header_includes': header_includes, | |
141 'interface_name': interface.name, | |
142 'is_active_dom_object': 'ActiveDOMObject' in extended_attributes, # [Ac
tiveDOMObject] | |
143 'is_audio_buffer': is_audio_buffer, | |
144 'is_check_security': is_check_security, | |
145 'is_dependent_lifetime': 'DependentLifetime' in extended_attributes, #
[DependentLifetime] | |
146 'is_document': is_document, | |
147 'is_event_target': inherits_interface(interface.name, 'EventTarget'), | |
148 'is_exception': interface.is_exception, | |
149 'is_will_be_garbage_collected': is_will_be_garbage_collected, | |
150 'is_node': inherits_interface(interface.name, 'Node'), | |
151 'measure_as': v8_utilities.measure_as(interface), # [MeasureAs] | |
152 'parent_interface': parent_interface, | |
153 'pass_ref_ptr': 'PassRefPtrWillBeRawPtr' | |
154 if is_will_be_garbage_collected else 'PassRefPtr', | |
155 'reachable_node_function': reachable_node_function, | |
156 'reachable_node_reference_function': reachable_node_reference_function, | |
157 'ref_ptr': 'RefPtrWillBeRawPtr' | |
158 if is_will_be_garbage_collected else 'RefPtr', | |
159 'runtime_enabled_function': runtime_enabled_function_name(interface), #
[RuntimeEnabled] | |
160 'set_wrapper_reference_to_list': set_wrapper_reference_to_list, | |
161 'special_wrap_for': special_wrap_for, | |
162 'v8_class': v8_utilities.v8_class_name(interface), | |
163 } | |
164 | |
165 # Constructors | |
166 constructors = [generate_constructor(interface, constructor) | |
167 for constructor in interface.constructors | |
168 # FIXME: shouldn't put named constructors with constructors | |
169 # (currently needed for Perl compatibility) | |
170 # Handle named constructors separately | |
171 if constructor.name == 'Constructor'] | |
172 generate_constructor_overloads(constructors) | |
173 | |
174 # [CustomConstructor] | |
175 custom_constructors = [{ # Only needed for computing interface length | |
176 'number_of_required_arguments': | |
177 number_of_required_arguments(constructor), | |
178 } for constructor in interface.custom_constructors] | |
179 | |
180 # [EventConstructor] | |
181 has_event_constructor = 'EventConstructor' in extended_attributes | |
182 any_type_attributes = [attribute for attribute in interface.attributes | |
183 if attribute.idl_type == 'any'] | |
184 if has_event_constructor: | |
185 includes.add('bindings/v8/Dictionary.h') | |
186 if any_type_attributes: | |
187 includes.add('bindings/v8/SerializedScriptValue.h') | |
188 | |
189 # [NamedConstructor] | |
190 named_constructor = generate_named_constructor(interface) | |
191 | |
192 if (constructors or custom_constructors or has_event_constructor or | |
193 named_constructor): | |
194 includes.add('bindings/v8/V8ObjectConstructor.h') | |
195 | |
196 template_contents.update({ | |
197 'any_type_attributes': any_type_attributes, | |
198 'constructors': constructors, | |
199 'has_custom_constructor': bool(custom_constructors), | |
200 'has_event_constructor': has_event_constructor, | |
201 'interface_length': | |
202 interface_length(interface, constructors + custom_constructors), | |
203 'is_constructor_call_with_document': has_extended_attribute_value( | |
204 interface, 'ConstructorCallWith', 'Document'), # [ConstructorCallWi
th=Document] | |
205 'is_constructor_call_with_execution_context': has_extended_attribute_val
ue( | |
206 interface, 'ConstructorCallWith', 'ExecutionContext'), # [Construct
orCallWith=ExeuctionContext] | |
207 'is_constructor_raises_exception': extended_attributes.get('RaisesExcept
ion') == 'Constructor', # [RaisesException=Constructor] | |
208 'named_constructor': named_constructor, | |
209 }) | |
210 | |
211 # Constants | |
212 template_contents.update({ | |
213 'constants': [generate_constant(constant) for constant in interface.cons
tants], | |
214 'do_not_check_constants': 'DoNotCheckConstants' in extended_attributes, | |
215 }) | |
216 | |
217 # Attributes | |
218 attributes = [v8_attributes.generate_attribute(interface, attribute) | |
219 for attribute in interface.attributes] | |
220 template_contents.update({ | |
221 'attributes': attributes, | |
222 'has_accessors': any(attribute['is_expose_js_accessors'] for attribute i
n attributes), | |
223 'has_attribute_configuration': any( | |
224 not (attribute['is_expose_js_accessors'] or | |
225 attribute['is_static'] or | |
226 attribute['runtime_enabled_function'] or | |
227 attribute['per_context_enabled_function']) | |
228 for attribute in attributes), | |
229 'has_constructor_attributes': any(attribute['constructor_type'] for attr
ibute in attributes), | |
230 'has_per_context_enabled_attributes': any(attribute['per_context_enabled
_function'] for attribute in attributes), | |
231 'has_replaceable_attributes': any(attribute['is_replaceable'] for attrib
ute in attributes), | |
232 }) | |
233 | |
234 # Methods | |
235 methods = [v8_methods.generate_method(interface, method) | |
236 for method in interface.operations | |
237 if method.name] # Skip anonymous special operations (methods) | |
238 generate_overloads(methods) | |
239 for method in methods: | |
240 method['do_generate_method_configuration'] = ( | |
241 method['do_not_check_signature'] and | |
242 not method['per_context_enabled_function'] and | |
243 # For overloaded methods, only generate one accessor | |
244 ('overload_index' not in method or method['overload_index'] == 1)) | |
245 | |
246 template_contents.update({ | |
247 'has_origin_safe_method_setter': any( | |
248 method['is_check_security_for_frame'] and not method['is_read_only'] | |
249 for method in methods), | |
250 'has_method_configuration': any(method['do_generate_method_configuration
'] for method in methods), | |
251 'has_per_context_enabled_methods': any(method['per_context_enabled_funct
ion'] for method in methods), | |
252 'methods': methods, | |
253 }) | |
254 | |
255 template_contents.update({ | |
256 'indexed_property_getter': indexed_property_getter(interface), | |
257 'indexed_property_setter': indexed_property_setter(interface), | |
258 'indexed_property_deleter': indexed_property_deleter(interface), | |
259 'is_override_builtins': 'OverrideBuiltins' in extended_attributes, | |
260 'named_property_getter': named_property_getter(interface), | |
261 'named_property_setter': named_property_setter(interface), | |
262 'named_property_deleter': named_property_deleter(interface), | |
263 }) | |
264 | |
265 return template_contents | |
266 | |
267 | |
268 # [DeprecateAs], [Reflect], [RuntimeEnabled] | |
269 def generate_constant(constant): | |
270 # (Blink-only) string literals are unquoted in tokenizer, must be re-quoted | |
271 # in C++. | |
272 if constant.idl_type == 'DOMString': | |
273 value = '"%s"' % constant.value | |
274 else: | |
275 value = constant.value | |
276 | |
277 extended_attributes = constant.extended_attributes | |
278 return { | |
279 'cpp_class': extended_attributes.get('ImplementedBy'), | |
280 'name': constant.name, | |
281 # FIXME: use 'reflected_name' as correct 'name' | |
282 'reflected_name': extended_attributes.get('Reflect', constant.name), | |
283 'runtime_enabled_function': runtime_enabled_function_name(constant), | |
284 'value': value, | |
285 } | |
286 | |
287 | |
288 ################################################################################ | |
289 # Overloads | |
290 ################################################################################ | |
291 | |
292 def generate_overloads(methods): | |
293 generate_overloads_by_type(methods, is_static=False) # Regular methods | |
294 generate_overloads_by_type(methods, is_static=True) | |
295 | |
296 | |
297 def generate_overloads_by_type(methods, is_static): | |
298 # Generates |overloads| template values and modifies |methods| in place; | |
299 # |is_static| flag used (instead of partitioning list in 2) because need to | |
300 # iterate over original list of methods to modify in place | |
301 method_counts = {} | |
302 for method in methods: | |
303 if method['is_static'] != is_static: | |
304 continue | |
305 name = method['name'] | |
306 method_counts.setdefault(name, 0) | |
307 method_counts[name] += 1 | |
308 | |
309 # Filter to only methods that are actually overloaded | |
310 overloaded_method_counts = dict((name, count) | |
311 for name, count in method_counts.iteritems() | |
312 if count > 1) | |
313 | |
314 # Add overload information only to overloaded methods, so template code can | |
315 # easily verify if a function is overloaded | |
316 method_overloads = {} | |
317 for method in methods: | |
318 name = method['name'] | |
319 if (method['is_static'] != is_static or | |
320 name not in overloaded_method_counts): | |
321 continue | |
322 # Overload index includes self, so first append, then compute index | |
323 method_overloads.setdefault(name, []).append(method) | |
324 method.update({ | |
325 'overload_index': len(method_overloads[name]), | |
326 'overload_resolution_expression': overload_resolution_expression(met
hod), | |
327 }) | |
328 | |
329 # Resolution function is generated after last overloaded function; | |
330 # package necessary information into |method.overloads| for that method. | |
331 for method in methods: | |
332 if (method['is_static'] != is_static or | |
333 'overload_index' not in method): | |
334 continue | |
335 name = method['name'] | |
336 if method['overload_index'] != overloaded_method_counts[name]: | |
337 continue | |
338 overloads = method_overloads[name] | |
339 minimum_number_of_required_arguments = min( | |
340 overload['number_of_required_arguments'] | |
341 for overload in overloads) | |
342 method['overloads'] = { | |
343 'has_exception_state': bool(minimum_number_of_required_arguments), | |
344 'methods': overloads, | |
345 'minimum_number_of_required_arguments': minimum_number_of_required_a
rguments, | |
346 'name': name, | |
347 } | |
348 | |
349 | |
350 def overload_resolution_expression(method): | |
351 # Expression is an OR of ANDs: each term in the OR corresponds to a | |
352 # possible argument count for a given method, with type checks. | |
353 # FIXME: Blink's overload resolution algorithm is incorrect, per: | |
354 # Implement WebIDL overload resolution algorithm. | |
355 # https://code.google.com/p/chromium/issues/detail?id=293561 | |
356 # | |
357 # Currently if distinguishing non-primitive type from primitive type, | |
358 # (e.g., sequence<DOMString> from DOMString or Dictionary from double) | |
359 # the method with a non-primitive type argument must appear *first* in the | |
360 # IDL file, since we're not adding a check to primitive types. | |
361 # FIXME: Once fixed, check IDLs, as usually want methods with primitive | |
362 # types to appear first (style-wise). | |
363 # | |
364 # Properly: | |
365 # 1. Compute effective overload set. | |
366 # 2. First check type list length. | |
367 # 3. If multiple entries for given length, compute distinguishing argument | |
368 # index and have check for that type. | |
369 arguments = method['arguments'] | |
370 overload_checks = [overload_check_expression(method, index) | |
371 # check *omitting* optional arguments at |index| and up: | |
372 # index 0 => argument_count 0 (no arguments) | |
373 # index 1 => argument_count 1 (index 0 argument only) | |
374 for index, argument in enumerate(arguments) | |
375 if argument['is_optional']] | |
376 # FIXME: this is wrong if a method has optional arguments and a variadic | |
377 # one, though there are not yet any examples of this | |
378 if not method['is_variadic']: | |
379 # Includes all optional arguments (len = last index + 1) | |
380 overload_checks.append(overload_check_expression(method, len(arguments))
) | |
381 return ' || '.join('(%s)' % check for check in overload_checks) | |
382 | |
383 | |
384 def overload_check_expression(method, argument_count): | |
385 overload_checks = ['info.Length() == %s' % argument_count] | |
386 arguments = method['arguments'][:argument_count] | |
387 overload_checks.extend(overload_check_argument(index, argument) | |
388 for index, argument in | |
389 enumerate(arguments)) | |
390 return ' && '.join('(%s)' % check for check in overload_checks if check) | |
391 | |
392 | |
393 def overload_check_argument(index, argument): | |
394 def null_or_optional_check(): | |
395 # If undefined is passed for an optional argument, the argument should | |
396 # be treated as missing; otherwise undefined is not allowed. | |
397 if argument['is_nullable']: | |
398 if argument['is_optional']: | |
399 return 'isUndefinedOrNull(%s)' | |
400 return '%s->IsNull()' | |
401 if argument['is_optional']: | |
402 return '%s->IsUndefined()' | |
403 return None | |
404 | |
405 cpp_value = 'info[%s]' % index | |
406 idl_type = argument['idl_type'] | |
407 # FIXME: proper type checking, sharing code with attributes and methods | |
408 if idl_type == 'DOMString' and argument['is_strict_type_checking']: | |
409 return ' || '.join(['isUndefinedOrNull(%s)' % cpp_value, | |
410 '%s->IsString()' % cpp_value, | |
411 '%s->IsObject()' % cpp_value]) | |
412 if v8_types.array_or_sequence_type(idl_type): | |
413 return '%s->IsArray()' % cpp_value | |
414 if v8_types.is_callback_interface(idl_type): | |
415 return ' || '.join(['%s->IsNull()' % cpp_value, | |
416 '%s->IsFunction()' % cpp_value]) | |
417 if v8_types.is_wrapper_type(idl_type): | |
418 type_check = 'V8{idl_type}::hasInstance({cpp_value}, info.GetIsolate())'
.format(idl_type=idl_type, cpp_value=cpp_value) | |
419 if argument['is_nullable']: | |
420 type_check = ' || '.join(['%s->IsNull()' % cpp_value, type_check]) | |
421 return type_check | |
422 if is_interface_type(idl_type): | |
423 # Non-wrapper types are just objects: we don't distinguish type | |
424 # We only allow undefined for non-wrapper types (notably Dictionary), | |
425 # as we need it for optional Dictionary arguments, but we don't want to | |
426 # change behavior of existing bindings for other types. | |
427 type_check = '%s->IsObject()' % cpp_value | |
428 added_check_template = null_or_optional_check() | |
429 if added_check_template: | |
430 type_check = ' || '.join([added_check_template % cpp_value, | |
431 type_check]) | |
432 return type_check | |
433 return None | |
434 | |
435 | |
436 ################################################################################ | |
437 # Constructors | |
438 ################################################################################ | |
439 | |
440 # [Constructor] | |
441 def generate_constructor(interface, constructor): | |
442 return { | |
443 'argument_list': constructor_argument_list(interface, constructor), | |
444 'arguments': [constructor_argument(argument, index) | |
445 for index, argument in enumerate(constructor.arguments)], | |
446 'has_exception_state': | |
447 # [RaisesException=Constructor] | |
448 interface.extended_attributes.get('RaisesException') == 'Constructor
' or | |
449 any(argument for argument in constructor.arguments | |
450 if argument.idl_type == 'SerializedScriptValue' or | |
451 v8_types.is_integer_type(argument.idl_type)), | |
452 'is_constructor': True, | |
453 'is_variadic': False, # Required for overload resolution | |
454 'number_of_required_arguments': | |
455 number_of_required_arguments(constructor), | |
456 } | |
457 | |
458 | |
459 def constructor_argument_list(interface, constructor): | |
460 arguments = [] | |
461 # [ConstructorCallWith=ExecutionContext] | |
462 if has_extended_attribute_value(interface, 'ConstructorCallWith', 'Execution
Context'): | |
463 arguments.append('context') | |
464 # [ConstructorCallWith=Document] | |
465 if has_extended_attribute_value(interface, 'ConstructorCallWith', 'Document'
): | |
466 arguments.append('document') | |
467 | |
468 arguments.extend([argument.name for argument in constructor.arguments]) | |
469 | |
470 # [RaisesException=Constructor] | |
471 if interface.extended_attributes.get('RaisesException') == 'Constructor': | |
472 arguments.append('exceptionState') | |
473 | |
474 return arguments | |
475 | |
476 | |
477 def constructor_argument(argument, index): | |
478 return { | |
479 'has_default': 'Default' in argument.extended_attributes, | |
480 'idl_type': argument.idl_type, | |
481 'index': index, | |
482 'is_nullable': False, # Required for overload resolution | |
483 'is_optional': argument.is_optional, | |
484 'is_strict_type_checking': False, # Required for overload resolution | |
485 'name': argument.name, | |
486 'v8_value_to_local_cpp_value': | |
487 v8_methods.v8_value_to_local_cpp_value(argument, index), | |
488 } | |
489 | |
490 | |
491 def generate_constructor_overloads(constructors): | |
492 if len(constructors) <= 1: | |
493 return | |
494 for overload_index, constructor in enumerate(constructors): | |
495 constructor.update({ | |
496 'overload_index': overload_index + 1, | |
497 'overload_resolution_expression': | |
498 overload_resolution_expression(constructor), | |
499 }) | |
500 | |
501 | |
502 # [NamedConstructor] | |
503 def generate_named_constructor(interface): | |
504 extended_attributes = interface.extended_attributes | |
505 if 'NamedConstructor' not in extended_attributes: | |
506 return None | |
507 # FIXME: parser should return named constructor separately; | |
508 # included in constructors (and only name stored in extended attribute) | |
509 # for Perl compatibility | |
510 idl_constructor = interface.constructors[0] | |
511 constructor = generate_constructor(interface, idl_constructor) | |
512 constructor['argument_list'].insert(0, '*document') | |
513 constructor['name'] = extended_attributes['NamedConstructor'] | |
514 return constructor | |
515 | |
516 | |
517 def number_of_required_arguments(constructor): | |
518 return len([argument for argument in constructor.arguments | |
519 if not argument.is_optional]) | |
520 | |
521 | |
522 def interface_length(interface, constructors): | |
523 # Docs: http://heycam.github.io/webidl/#es-interface-call | |
524 if 'EventConstructor' in interface.extended_attributes: | |
525 return 1 | |
526 if not constructors: | |
527 return 0 | |
528 return min(constructor['number_of_required_arguments'] | |
529 for constructor in constructors) | |
530 | |
531 | |
532 ################################################################################ | |
533 # Special operations (methods) | |
534 # http://heycam.github.io/webidl/#idl-special-operations | |
535 ################################################################################ | |
536 | |
537 def property_getter(getter, cpp_arguments): | |
538 def is_null_expression(idl_type): | |
539 if v8_types.is_union_type(idl_type): | |
540 return ' && '.join('!result%sEnabled' % i | |
541 for i, _ in | |
542 enumerate(idl_type.union_member_types)) | |
543 if idl_type == 'DOMString': | |
544 return 'result.isNull()' | |
545 if is_interface_type(idl_type): | |
546 return '!result' | |
547 return '' | |
548 | |
549 idl_type = getter.idl_type | |
550 extended_attributes = getter.extended_attributes | |
551 is_raises_exception = 'RaisesException' in extended_attributes | |
552 | |
553 if v8_types.is_union_type(idl_type): | |
554 release = [v8_types.is_interface_type(union_member_type) | |
555 for union_member_type in idl_type.union_member_types] | |
556 else: | |
557 release = v8_types.is_interface_type(idl_type) | |
558 | |
559 # FIXME: make more generic, so can use v8_methods.cpp_value | |
560 cpp_method_name = 'imp->%s' % cpp_name(getter) | |
561 | |
562 if is_raises_exception: | |
563 cpp_arguments.append('exceptionState') | |
564 this_union_arguments = v8_methods.union_arguments(idl_type) | |
565 if this_union_arguments: | |
566 cpp_arguments.extend(this_union_arguments) | |
567 | |
568 cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments)) | |
569 | |
570 return { | |
571 'cpp_type': v8_types.cpp_type(idl_type), | |
572 'cpp_value': cpp_value, | |
573 'is_custom': | |
574 'Custom' in extended_attributes and | |
575 (not extended_attributes['Custom'] or | |
576 has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')), | |
577 'is_custom_property_enumerator': has_extended_attribute_value( | |
578 getter, 'Custom', 'PropertyEnumerator'), | |
579 'is_custom_property_query': has_extended_attribute_value( | |
580 getter, 'Custom', 'PropertyQuery'), | |
581 'is_enumerable': 'NotEnumerable' not in extended_attributes, | |
582 'is_null_expression': is_null_expression(idl_type), | |
583 'is_raises_exception': is_raises_exception, | |
584 'name': cpp_name(getter), | |
585 'union_arguments': v8_methods.union_arguments(idl_type), | |
586 'v8_set_return_value': v8_types.v8_set_return_value(idl_type, 'result',
extended_attributes=extended_attributes, script_wrappable='imp', release=release
), | |
587 } | |
588 | |
589 | |
590 def property_setter(setter): | |
591 idl_type = setter.arguments[1].idl_type | |
592 extended_attributes = setter.extended_attributes | |
593 is_raises_exception = 'RaisesException' in extended_attributes | |
594 return { | |
595 'has_strict_type_checking': | |
596 'StrictTypeChecking' in extended_attributes and | |
597 v8_types.is_wrapper_type(idl_type), | |
598 'idl_type': idl_type, | |
599 'is_custom': 'Custom' in extended_attributes, | |
600 'has_exception_state': is_raises_exception or | |
601 v8_types.is_integer_type(idl_type), | |
602 'is_raises_exception': is_raises_exception, | |
603 'name': cpp_name(setter), | |
604 'v8_value_to_local_cpp_value': v8_types.v8_value_to_local_cpp_value( | |
605 idl_type, extended_attributes, 'jsValue', 'propertyValue'), | |
606 } | |
607 | |
608 | |
609 def property_deleter(deleter): | |
610 idl_type = deleter.idl_type | |
611 if idl_type != 'boolean': | |
612 raise Exception( | |
613 'Only deleters with boolean type are allowed, but type is "%s"' % | |
614 idl_type) | |
615 extended_attributes = deleter.extended_attributes | |
616 return { | |
617 'is_custom': 'Custom' in extended_attributes, | |
618 'is_raises_exception': 'RaisesException' in extended_attributes, | |
619 'name': cpp_name(deleter), | |
620 } | |
621 | |
622 | |
623 ################################################################################ | |
624 # Indexed properties | |
625 # http://heycam.github.io/webidl/#idl-indexed-properties | |
626 ################################################################################ | |
627 | |
628 def indexed_property_getter(interface): | |
629 try: | |
630 # Find indexed property getter, if present; has form: | |
631 # getter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1) | |
632 getter = next( | |
633 method | |
634 for method in interface.operations | |
635 if ('getter' in method.specials and | |
636 len(method.arguments) == 1 and | |
637 method.arguments[0].idl_type == 'unsigned long')) | |
638 except StopIteration: | |
639 return None | |
640 | |
641 return property_getter(getter, ['index']) | |
642 | |
643 | |
644 def indexed_property_setter(interface): | |
645 try: | |
646 # Find indexed property setter, if present; has form: | |
647 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE
ARG2) | |
648 setter = next( | |
649 method | |
650 for method in interface.operations | |
651 if ('setter' in method.specials and | |
652 len(method.arguments) == 2 and | |
653 method.arguments[0].idl_type == 'unsigned long')) | |
654 except StopIteration: | |
655 return None | |
656 | |
657 return property_setter(setter) | |
658 | |
659 | |
660 def indexed_property_deleter(interface): | |
661 try: | |
662 # Find indexed property deleter, if present; has form: | |
663 # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG) | |
664 deleter = next( | |
665 method | |
666 for method in interface.operations | |
667 if ('deleter' in method.specials and | |
668 len(method.arguments) == 1 and | |
669 method.arguments[0].idl_type == 'unsigned long')) | |
670 except StopIteration: | |
671 return None | |
672 | |
673 return property_deleter(deleter) | |
674 | |
675 | |
676 ################################################################################ | |
677 # Named properties | |
678 # http://heycam.github.io/webidl/#idl-named-properties | |
679 ################################################################################ | |
680 | |
681 def named_property_getter(interface): | |
682 try: | |
683 # Find named property getter, if present; has form: | |
684 # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1) | |
685 getter = next( | |
686 method | |
687 for method in interface.operations | |
688 if ('getter' in method.specials and | |
689 len(method.arguments) == 1 and | |
690 method.arguments[0].idl_type == 'DOMString')) | |
691 except StopIteration: | |
692 return None | |
693 | |
694 getter.name = getter.name or 'anonymousNamedGetter' | |
695 return property_getter(getter, ['propertyName']) | |
696 | |
697 | |
698 def named_property_setter(interface): | |
699 try: | |
700 # Find named property setter, if present; has form: | |
701 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2
) | |
702 setter = next( | |
703 method | |
704 for method in interface.operations | |
705 if ('setter' in method.specials and | |
706 len(method.arguments) == 2 and | |
707 method.arguments[0].idl_type == 'DOMString')) | |
708 except StopIteration: | |
709 return None | |
710 | |
711 return property_setter(setter) | |
712 | |
713 | |
714 def named_property_deleter(interface): | |
715 try: | |
716 # Find named property deleter, if present; has form: | |
717 # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG) | |
718 deleter = next( | |
719 method | |
720 for method in interface.operations | |
721 if ('deleter' in method.specials and | |
722 len(method.arguments) == 1 and | |
723 method.arguments[0].idl_type == 'DOMString')) | |
724 except StopIteration: | |
725 return None | |
726 | |
727 return property_deleter(deleter) | |
OLD | NEW |