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

Side by Side Diff: sky/engine/bindings/scripts/v8_interface.py

Issue 922053002: Remove unused V8 integration code in Sky (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/engine/bindings/scripts/v8_globals.py ('k') | sky/engine/bindings/scripts/v8_methods.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 # coding=utf-8
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 """Generate template values for an interface.
31
32 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
33 """
34
35 from collections import defaultdict
36 import itertools
37 from operator import itemgetter
38
39 import idl_definitions
40 from idl_definitions import IdlOperation
41 import idl_types
42 from idl_types import IdlType, inherits_interface
43 import v8_attributes
44 from v8_globals import includes
45 import v8_methods
46 import v8_types
47 from v8_types import cpp_template_type
48 import v8_utilities
49 from v8_utilities import (capitalize, conditional_string, cpp_name,
50 has_extended_attribute_value, runtime_enabled_function _name,
51 extended_attribute_value_as_list)
52
53
54 INTERFACE_H_INCLUDES = frozenset([
55 'bindings/core/v8/ScriptWrappable.h',
56 'bindings/core/v8/V8Binding.h',
57 'bindings/core/v8/V8DOMWrapper.h',
58 'bindings/core/v8/WrapperTypeInfo.h',
59 'platform/heap/Handle.h',
60 ])
61 INTERFACE_CPP_INCLUDES = frozenset([
62 'bindings/core/v8/ExceptionState.h',
63 'bindings/core/v8/V8DOMConfiguration.h',
64 'bindings/core/v8/V8HiddenValue.h',
65 'bindings/core/v8/V8ObjectConstructor.h',
66 'core/dom/Document.h',
67 'platform/RuntimeEnabledFeatures.h',
68 'platform/TraceEvent.h',
69 'wtf/GetPtr.h',
70 'wtf/RefPtr.h',
71 ])
72
73
74 def interface_context(interface):
75 includes.clear()
76 includes.update(INTERFACE_CPP_INCLUDES)
77 header_includes = set(INTERFACE_H_INCLUDES)
78
79 parent_interface = interface.parent
80 if parent_interface:
81 header_includes.update(v8_types.includes_for_interface(parent_interface) )
82 extended_attributes = interface.extended_attributes
83
84 is_document = inherits_interface(interface.name, 'Document')
85 if is_document:
86 includes.update(['bindings/core/v8/ScriptController.h',
87 'bindings/core/v8/WindowProxy.h',
88 'core/frame/LocalFrame.h'])
89
90 # [ActiveDOMObject]
91 is_active_dom_object = 'ActiveDOMObject' in extended_attributes
92
93 # [CheckSecurity]
94 is_check_security = 'CheckSecurity' in extended_attributes
95 if is_check_security:
96 includes.add('bindings/core/v8/BindingSecurity.h')
97
98 # [DependentLifetime]
99 is_dependent_lifetime = 'DependentLifetime' in extended_attributes
100
101 # [Iterable]
102 iterator_method = None
103 if 'Iterable' in extended_attributes:
104 iterator_operation = IdlOperation(interface.idl_name)
105 iterator_operation.name = 'iterator'
106 iterator_operation.idl_type = IdlType('Iterator')
107 iterator_operation.extended_attributes['RaisesException'] = None
108 iterator_operation.extended_attributes['CallWith'] = 'ScriptState'
109 iterator_method = v8_methods.method_context(interface,
110 iterator_operation)
111
112 # [MeasureAs]
113 is_measure_as = 'MeasureAs' in extended_attributes
114
115 # [SetWrapperReferenceFrom]
116 reachable_node_function = extended_attributes.get('SetWrapperReferenceFrom')
117 if reachable_node_function:
118 includes.update(['bindings/core/v8/V8GCController.h',
119 'core/dom/Element.h'])
120
121 # [SetWrapperReferenceTo]
122 set_wrapper_reference_to_list = [{
123 'name': argument.name,
124 # FIXME: properly should be:
125 # 'cpp_type': argument.idl_type.cpp_type_args(raw_type=True),
126 # (if type is non-wrapper type like NodeFilter, normally RefPtr)
127 # Raw pointers faster though, and NodeFilter hacky anyway.
128 'cpp_type': argument.idl_type.implemented_as + '*',
129 'idl_type': argument.idl_type,
130 'v8_type': v8_types.v8_type(argument.idl_type.name),
131 } for argument in extended_attributes.get('SetWrapperReferenceTo', [])]
132 for set_wrapper_reference_to in set_wrapper_reference_to_list:
133 set_wrapper_reference_to['idl_type'].add_includes_for_type()
134
135 # [NotScriptWrappable]
136 is_script_wrappable = 'NotScriptWrappable' not in extended_attributes
137
138 # [SpecialWrapFor]
139 if 'SpecialWrapFor' in extended_attributes:
140 special_wrap_for = extended_attribute_value_as_list(interface, 'SpecialW rapFor')
141 else:
142 special_wrap_for = []
143 for special_wrap_interface in special_wrap_for:
144 v8_types.add_includes_for_interface(special_wrap_interface)
145
146 # [Custom=Wrap], [SetWrapperReferenceFrom]
147 has_visit_dom_wrapper = (
148 has_extended_attribute_value(interface, 'Custom', 'VisitDOMWrapper') or
149 reachable_node_function or
150 set_wrapper_reference_to_list)
151
152 wrapper_class_id = ('NodeClassId' if inherits_interface(interface.name, 'Nod e') else 'ObjectClassId')
153
154 context = {
155 'conditional_string': conditional_string(interface), # [Conditional]
156 'cpp_class': cpp_name(interface),
157 # FIXME: Remove 'EventTarget' special handling, http://crbug.com/383699
158 'has_access_check_callbacks': (is_check_security and
159 interface.name != 'Window' and
160 interface.name != 'EventTarget'),
161 'has_custom_legacy_call_as_function': has_extended_attribute_value(inter face, 'Custom', 'LegacyCallAsFunction'), # [Custom=LegacyCallAsFunction]
162 'has_custom_to_v8': has_extended_attribute_value(interface, 'Custom', 'T oV8'), # [Custom=ToV8]
163 'has_custom_wrap': has_extended_attribute_value(interface, 'Custom', 'Wr ap'), # [Custom=Wrap]
164 'has_visit_dom_wrapper': has_visit_dom_wrapper,
165 'header_includes': header_includes,
166 'interface_name': interface.name,
167 'is_active_dom_object': is_active_dom_object,
168 'is_check_security': is_check_security,
169 'is_dependent_lifetime': is_dependent_lifetime,
170 'is_document': is_document,
171 'is_event_target': inherits_interface(interface.name, 'EventTarget'),
172 'is_exception': interface.is_exception,
173 'is_node': inherits_interface(interface.name, 'Node'),
174 'is_script_wrappable': is_script_wrappable,
175 'iterator_method': iterator_method,
176 'lifetime': 'Dependent'
177 if (has_visit_dom_wrapper or
178 is_active_dom_object or
179 is_dependent_lifetime)
180 else 'Independent',
181 'measure_as': v8_utilities.measure_as(interface), # [MeasureAs]
182 'parent_interface': parent_interface,
183 'pass_cpp_type': cpp_template_type(
184 'PassRefPtr',
185 cpp_name(interface)),
186 'reachable_node_function': reachable_node_function,
187 'runtime_enabled_function': runtime_enabled_function_name(interface), # [RuntimeEnabled]
188 'set_wrapper_reference_to_list': set_wrapper_reference_to_list,
189 'special_wrap_for': special_wrap_for,
190 'v8_class': v8_utilities.v8_class_name(interface),
191 'wrapper_class_id': wrapper_class_id,
192 }
193
194 # Constructors
195 constructors = [constructor_context(interface, constructor)
196 for constructor in interface.constructors
197 # FIXME: shouldn't put named constructors with constructors
198 # (currently needed for Perl compatibility)
199 # Handle named constructors separately
200 if constructor.name == 'Constructor']
201 if len(constructors) > 1:
202 context['constructor_overloads'] = overloads_context(constructors)
203
204 # [CustomConstructor]
205 custom_constructors = [{ # Only needed for computing interface length
206 'number_of_required_arguments':
207 number_of_required_arguments(constructor),
208 } for constructor in interface.custom_constructors]
209
210 # [EventConstructor]
211 has_event_constructor = 'EventConstructor' in extended_attributes
212 any_type_attributes = [attribute for attribute in interface.attributes
213 if attribute.idl_type.name == 'Any']
214 if has_event_constructor:
215 includes.add('bindings/core/v8/Dictionary.h')
216 if any_type_attributes:
217 includes.add('bindings/core/v8/SerializedScriptValue.h')
218
219 # [NamedConstructor]
220 named_constructor = named_constructor_context(interface)
221
222 if (constructors or custom_constructors or has_event_constructor or
223 named_constructor):
224 includes.add('bindings/core/v8/V8ObjectConstructor.h')
225 includes.add('core/frame/LocalDOMWindow.h')
226
227 context.update({
228 'any_type_attributes': any_type_attributes,
229 'constructors': constructors,
230 'has_custom_constructor': bool(custom_constructors),
231 'has_event_constructor': has_event_constructor,
232 'interface_length':
233 interface_length(interface, constructors + custom_constructors),
234 'is_constructor_raises_exception': extended_attributes.get('RaisesExcept ion') == 'Constructor', # [RaisesException=Constructor]
235 'named_constructor': named_constructor,
236 })
237
238 constants = [constant_context(constant) for constant in interface.constants]
239
240 # Constants
241 context.update({
242 'constants': constants,
243 'do_not_check_constants': 'DoNotCheckConstants' in extended_attributes,
244 'has_constant_configuration': any(
245 not constant['runtime_enabled_function']
246 for constant in constants),
247 })
248
249 # Attributes
250 attributes = [v8_attributes.attribute_context(interface, attribute)
251 for attribute in interface.attributes]
252 context.update({
253 'attributes': attributes,
254 'has_accessors': any(attribute['is_expose_js_accessors'] and attribute[' should_be_exposed_to_script'] for attribute in attributes),
255 'has_attribute_configuration': any(
256 not (attribute['is_expose_js_accessors'] or
257 attribute['is_static'] or
258 attribute['runtime_enabled_function'])
259 and attribute['should_be_exposed_to_script']
260 for attribute in attributes),
261 'has_conditional_attributes': any(attribute['exposed_test'] for attribut e in attributes),
262 'has_constructor_attributes': any(attribute['constructor_type'] for attr ibute in attributes),
263 'has_replaceable_attributes': any(attribute['is_replaceable'] for attrib ute in attributes),
264 })
265
266 # Methods
267 methods = [v8_methods.method_context(interface, method)
268 for method in interface.operations
269 if method.name] # Skip anonymous special operations (methods)
270 compute_method_overloads_context(methods)
271
272 # Stringifier
273 if interface.stringifier:
274 stringifier = interface.stringifier
275 method = IdlOperation(interface.idl_name)
276 method.name = 'toString'
277 method.idl_type = IdlType('DOMString')
278 method.extended_attributes.update(stringifier.extended_attributes)
279 if stringifier.attribute:
280 method.extended_attributes['ImplementedAs'] = stringifier.attribute. name
281 elif stringifier.operation:
282 method.extended_attributes['ImplementedAs'] = stringifier.operation. name
283 methods.append(v8_methods.method_context(interface, method))
284
285 conditionally_enabled_methods = []
286 custom_registration_methods = []
287 method_configuration_methods = []
288
289 for method in methods:
290 # Skip all but one method in each set of overloaded methods.
291 if 'overload_index' in method and 'overloads' not in method:
292 continue
293
294 if 'overloads' in method:
295 overloads = method['overloads']
296 conditionally_exposed_function = overloads['exposed_test_all']
297 runtime_enabled_function = overloads['runtime_enabled_function_all']
298 has_custom_registration = overloads['has_custom_registration_all']
299 else:
300 conditionally_exposed_function = method['exposed_test']
301 runtime_enabled_function = method['runtime_enabled_function']
302 has_custom_registration = method['has_custom_registration']
303
304 if conditionally_exposed_function:
305 conditionally_enabled_methods.append(method)
306 continue
307 if runtime_enabled_function or has_custom_registration:
308 custom_registration_methods.append(method)
309 continue
310 if method['should_be_exposed_to_script']:
311 method_configuration_methods.append(method)
312
313 for method in methods:
314 # The value of the Function object’s “length” property is a Number
315 # determined as follows:
316 # 1. Let S be the effective overload set for regular operations (if the
317 # operation is a regular operation) or for static operations (if the
318 # operation is a static operation) with identifier id on interface I and
319 # with argument count 0.
320 # 2. Return the length of the shortest argument list of the entries in S .
321 # FIXME: This calculation doesn't take into account whether runtime
322 # enabled overloads are actually enabled, so length may be incorrect.
323 # E.g., [RuntimeEnabled=Foo] void f(); void f(long x);
324 # should have length 1 if Foo is not enabled, but length 0 if it is.
325 method['length'] = (method['overloads']['minarg'] if 'overloads' in meth od else
326 method['number_of_required_arguments'])
327
328 context.update({
329 'conditionally_enabled_methods': conditionally_enabled_methods,
330 'custom_registration_methods': custom_registration_methods,
331 'has_origin_safe_method_setter': any(
332 method['is_check_security_for_frame'] and not method['is_read_only']
333 for method in methods),
334 'has_private_script': any(attribute['is_implemented_in_private_script'] for attribute in attributes) or
335 any(method['is_implemented_in_private_script'] for method in methods ),
336 'method_configuration_methods': method_configuration_methods,
337 'methods': methods,
338 })
339
340 context.update({
341 'indexed_property_getter': indexed_property_getter(interface),
342 'indexed_property_setter': indexed_property_setter(interface),
343 'indexed_property_deleter': indexed_property_deleter(interface),
344 'is_override_builtins': 'OverrideBuiltins' in extended_attributes,
345 'named_property_getter': named_property_getter(interface),
346 'named_property_setter': named_property_setter(interface),
347 'named_property_deleter': named_property_deleter(interface),
348 })
349
350 return context
351
352
353 # [DeprecateAs], [Reflect], [RuntimeEnabled]
354 def constant_context(constant):
355 # (Blink-only) string literals are unquoted in tokenizer, must be re-quoted
356 # in C++.
357 if constant.idl_type.name == 'String':
358 value = '"%s"' % constant.value
359 else:
360 value = constant.value
361
362 extended_attributes = constant.extended_attributes
363 return {
364 'cpp_class': extended_attributes.get('PartialInterfaceImplementedAs'),
365 'idl_type': constant.idl_type.name,
366 'name': constant.name,
367 # FIXME: use 'reflected_name' as correct 'name'
368 'reflected_name': extended_attributes.get('Reflect', constant.name),
369 'runtime_enabled_function': runtime_enabled_function_name(constant),
370 'value': value,
371 }
372
373
374 ################################################################################
375 # Overloads
376 ################################################################################
377
378 def compute_method_overloads_context(methods):
379 # Regular methods
380 compute_method_overloads_context_by_type([method for method in methods
381 if not method['is_static']])
382 # Static methods
383 compute_method_overloads_context_by_type([method for method in methods
384 if method['is_static']])
385
386
387 def compute_method_overloads_context_by_type(methods):
388 """Computes |method.overload*| template values.
389
390 Called separately for static and non-static (regular) methods,
391 as these are overloaded separately.
392 Modifies |method| in place for |method| in |methods|.
393 Doesn't change the |methods| list itself (only the values, i.e. individual
394 methods), so ok to treat these separately.
395 """
396 # Add overload information only to overloaded methods, so template code can
397 # easily verify if a function is overloaded
398 for name, overloads in method_overloads_by_name(methods):
399 # Resolution function is generated after last overloaded function;
400 # package necessary information into |method.overloads| for that method.
401 overloads[-1]['overloads'] = overloads_context(overloads)
402 overloads[-1]['overloads']['name'] = name
403
404
405 def method_overloads_by_name(methods):
406 """Returns generator of overloaded methods by name: [name, [method]]"""
407 # Filter to only methods that are actually overloaded
408 method_counts = Counter(method['name'] for method in methods)
409 overloaded_method_names = set(name
410 for name, count in method_counts.iteritems()
411 if count > 1)
412 overloaded_methods = [method for method in methods
413 if method['name'] in overloaded_method_names]
414
415 # Group by name (generally will be defined together, but not necessarily)
416 return sort_and_groupby(overloaded_methods, itemgetter('name'))
417
418
419 def overloads_context(overloads):
420 """Returns |overloads| template values for a single name.
421
422 Sets |method.overload_index| in place for |method| in |overloads|
423 and returns dict of overall overload template values.
424 """
425 assert len(overloads) > 1 # only apply to overloaded names
426 for index, method in enumerate(overloads, 1):
427 method['overload_index'] = index
428
429 effective_overloads_by_length = effective_overload_set_by_length(overloads)
430 lengths = [length for length, _ in effective_overloads_by_length]
431 name = overloads[0].get('name', '<constructor>')
432
433 # Check and fail if all overloads with the shortest acceptable arguments
434 # list are runtime enabled, since we would otherwise set 'length' on the
435 # function object to an incorrect value when none of those overloads were
436 # actually enabled at runtime. The exception is if all overloads are
437 # controlled by the same runtime enabled feature, in which case there would
438 # be no function object at all if it is not enabled.
439 shortest_overloads = effective_overloads_by_length[0][1]
440 if (all(method.get('runtime_enabled_function')
441 for method, _, _ in shortest_overloads) and
442 not common_value(overloads, 'runtime_enabled_function')):
443 raise ValueError('Function.length of %s depends on runtime enabled featu res' % name)
444
445 # Check and fail if overloads disagree on any of the extended attributes
446 # that affect how the method should be registered.
447 # Skip the check for overloaded constructors, since they don't support any
448 # of the extended attributes in question.
449 if not overloads[0].get('is_constructor'):
450 overload_extended_attributes = [
451 method['custom_registration_extended_attributes']
452 for method in overloads]
453 for extended_attribute in v8_methods.CUSTOM_REGISTRATION_EXTENDED_ATTRIB UTES:
454 if common_key(overload_extended_attributes, extended_attribute) is N one:
455 raise ValueError('Overloads of %s have conflicting extended attr ibute %s'
456 % (name, extended_attribute))
457
458 # Check and fail if overloads disagree about whether the return type
459 # is a Promise or not.
460 promise_overload_count = sum(1 for method in overloads if method.get('idl_ty pe') == 'Promise')
461 if promise_overload_count not in (0, len(overloads)):
462 raise ValueError('Overloads of %s have conflicting Promise/non-Promise t ypes'
463 % (name))
464
465 return {
466 'deprecate_all_as': common_value(overloads, 'deprecate_as'), # [Depreca teAs]
467 'exposed_test_all': common_value(overloads, 'exposed_test'), # [Exposed ]
468 'has_custom_registration_all': common_value(overloads, 'has_custom_regis tration'),
469 'length_tests_methods': length_tests_methods(effective_overloads_by_leng th),
470 # 1. Let maxarg be the length of the longest type list of the
471 # entries in S.
472 'maxarg': lengths[-1],
473 'measure_all_as': common_value(overloads, 'measure_as'), # [MeasureAs]
474 'minarg': lengths[0],
475 'runtime_enabled_function_all': common_value(overloads, 'runtime_enabled _function'), # [RuntimeEnabled]
476 'valid_arities': lengths
477 # Only need to report valid arities if there is a gap in the
478 # sequence of possible lengths, otherwise invalid length means
479 # "not enough arguments".
480 if lengths[-1] - lengths[0] != len(lengths) - 1 else None,
481 }
482
483
484 def effective_overload_set(F):
485 """Returns the effective overload set of an overloaded function.
486
487 An effective overload set is the set of overloaded functions + signatures
488 (type list of arguments, with optional and variadic arguments included or
489 not), and is used in the overload resolution algorithm.
490
491 For example, given input [f1(optional long x), f2(DOMString s)], the output
492 is informally [f1(), f1(long), f2(DOMString)], and formally
493 [(f1, [], []), (f1, [long], [optional]), (f2, [DOMString], [required])].
494
495 Currently the optionality list is a list of |is_optional| booleans (True
496 means optional, False means required); to support variadics this needs to
497 be tri-valued as required, optional, or variadic.
498
499 Formally:
500 An effective overload set represents the allowable invocations for a
501 particular operation, constructor (specified with [Constructor] or
502 [NamedConstructor]), legacy caller or callback function.
503
504 An additional argument N (argument count) is needed when overloading
505 variadics, but we don't use that currently.
506
507 Spec: http://heycam.github.io/webidl/#dfn-effective-overload-set
508
509 Formally the input and output lists are sets, but methods are stored
510 internally as dicts, which can't be stored in a set because they are not
511 hashable, so we use lists instead.
512
513 Arguments:
514 F: list of overloads for a given callable name.
515
516 Returns:
517 S: list of tuples of the form (callable, type list, optionality list).
518 """
519 # Code closely follows the algorithm in the spec, for clarity and
520 # correctness, and hence is not very Pythonic.
521
522 # 1. Initialize S to ∅.
523 # (We use a list because we can't use a set, as noted above.)
524 S = []
525
526 # 2. Let F be a set with elements as follows, according to the kind of
527 # effective overload set:
528 # (Passed as argument, nothing to do.)
529
530 # 3. & 4. (maxarg, m) are only needed for variadics, not used.
531
532 # 5. For each operation, extended attribute or callback function X in F:
533 for X in F: # X is the "callable", F is the overloads.
534 arguments = X['arguments']
535 # 1. Let n be the number of arguments X is declared to take.
536 n = len(arguments)
537 # 2. Let t0..n−1 be a list of types, where ti is the type of X’s
538 # argument at index i.
539 # (“type list”)
540 t = tuple(argument['idl_type_object'] for argument in arguments)
541 # 3. Let o0..n−1 be a list of optionality values, where oi is “variadic”
542 # if X’s argument at index i is a final, variadic argument, “optional”
543 # if the argument is optional, and “required” otherwise.
544 # (“optionality list”)
545 # (We’re just using a boolean for optional vs. required.)
546 o = tuple(argument['is_optional'] for argument in arguments)
547 # 4. Add to S the tuple <X, t0..n−1, o0..n−1>.
548 S.append((X, t, o))
549 # 5. If X is declared to be variadic, then:
550 # (Not used, so not implemented.)
551 # 6. Initialize i to n−1.
552 i = n - 1
553 # 7. While i ≥ 0:
554 # Spec bug (fencepost error); should be “While i > 0:”
555 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=25590
556 while i > 0:
557 # 1. If argument i of X is not optional, then break this loop.
558 if not o[i]:
559 break
560 # 2. Otherwise, add to S the tuple <X, t0..i−1, o0..i−1>.
561 S.append((X, t[:i], o[:i]))
562 # 3. Set i to i−1.
563 i = i - 1
564 # 8. If n > 0 and all arguments of X are optional, then add to S the
565 # tuple <X, (), ()> (where “()” represents the empty list).
566 if n > 0 and all(oi for oi in o):
567 S.append((X, [], []))
568 # 6. The effective overload set is S.
569 return S
570
571
572 def effective_overload_set_by_length(overloads):
573 def type_list_length(entry):
574 # Entries in the effective overload set are 3-tuples:
575 # (callable, type list, optionality list)
576 return len(entry[1])
577
578 effective_overloads = effective_overload_set(overloads)
579 return list(sort_and_groupby(effective_overloads, type_list_length))
580
581
582 def distinguishing_argument_index(entries):
583 """Returns the distinguishing argument index for a sequence of entries.
584
585 Entries are elements of the effective overload set with the same number
586 of arguments (formally, same type list length), each a 3-tuple of the form
587 (callable, type list, optionality list).
588
589 Spec: http://heycam.github.io/webidl/#dfn-distinguishing-argument-index
590
591 If there is more than one entry in an effective overload set that has a
592 given type list length, then for those entries there must be an index i
593 such that for each pair of entries the types at index i are
594 distinguishable.
595 The lowest such index is termed the distinguishing argument index for the
596 entries of the effective overload set with the given type list length.
597 """
598 # Only applicable “If there is more than one entry”
599 assert len(entries) > 1
600 type_lists = [tuple(idl_type.name for idl_type in entry[1])
601 for entry in entries]
602 type_list_length = len(type_lists[0])
603 # Only applicable for entries that “[have] a given type list length”
604 assert all(len(type_list) == type_list_length for type_list in type_lists)
605 name = entries[0][0].get('name', 'Constructor') # for error reporting
606
607 # The spec defines the distinguishing argument index by conditions it must
608 # satisfy, but does not give an algorithm.
609 #
610 # We compute the distinguishing argument index by first computing the
611 # minimum index where not all types are the same, and then checking that
612 # all types in this position are distinguishable (and the optionality lists
613 # up to this point are identical), since "minimum index where not all types
614 # are the same" is a *necessary* condition, and more direct to check than
615 # distinguishability.
616 types_by_index = (set(types) for types in zip(*type_lists))
617 try:
618 # “In addition, for each index j, where j is less than the
619 # distinguishing argument index for a given type list length, the types
620 # at index j in all of the entries’ type lists must be the same”
621 index = next(i for i, types in enumerate(types_by_index)
622 if len(types) > 1)
623 except StopIteration:
624 raise ValueError('No distinguishing index found for %s, length %s:\n'
625 'All entries have the same type list:\n'
626 '%s' % (name, type_list_length, type_lists[0]))
627 # Check optionality
628 # “and the booleans in the corresponding list indicating argument
629 # optionality must be the same.”
630 # FIXME: spec typo: optionality value is no longer a boolean
631 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=25628
632 initial_optionality_lists = set(entry[2][:index] for entry in entries)
633 if len(initial_optionality_lists) > 1:
634 raise ValueError(
635 'Invalid optionality lists for %s, length %s:\n'
636 'Optionality lists differ below distinguishing argument index %s:\n'
637 '%s'
638 % (name, type_list_length, index, set(initial_optionality_lists)))
639
640 # Check distinguishability
641 # http://heycam.github.io/webidl/#dfn-distinguishable
642 # Use names to check for distinct types, since objects are distinct
643 # FIXME: check distinguishability more precisely, for validation
644 distinguishing_argument_type_names = [type_list[index]
645 for type_list in type_lists]
646 if (len(set(distinguishing_argument_type_names)) !=
647 len(distinguishing_argument_type_names)):
648 raise ValueError('Types in distinguishing argument are not distinct:\n'
649 '%s' % distinguishing_argument_type_names)
650
651 return index
652
653
654 def length_tests_methods(effective_overloads_by_length):
655 """Returns sorted list of resolution tests and associated methods, by length .
656
657 This builds the main data structure for the overload resolution loop.
658 For a given argument length, bindings test argument at distinguishing
659 argument index, in order given by spec: if it is compatible with
660 (optionality or) type required by an overloaded method, resolve to that
661 method.
662
663 Returns:
664 [(length, [(test, method)])]
665 """
666 return [(length, list(resolution_tests_methods(effective_overloads)))
667 for length, effective_overloads in effective_overloads_by_length]
668
669
670 def resolution_tests_methods(effective_overloads):
671 """Yields resolution test and associated method, in resolution order, for ef fective overloads of a given length.
672
673 This is the heart of the resolution algorithm.
674 http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
675
676 Note that a given method can be listed multiple times, with different tests!
677 This is to handle implicit type conversion.
678
679 Returns:
680 [(test, method)]
681 """
682 methods = [effective_overload[0]
683 for effective_overload in effective_overloads]
684 if len(methods) == 1:
685 # If only one method with a given length, no test needed
686 yield 'true', methods[0]
687 return
688
689 # 6. If there is more than one entry in S, then set d to be the
690 # distinguishing argument index for the entries of S.
691 index = distinguishing_argument_index(effective_overloads)
692 # (7-9 are for handling |undefined| values for optional arguments before
693 # the distinguishing argument (as “missing”), so you can specify only some
694 # optional arguments. We don’t support this, so we skip these steps.)
695 # 10. If i = d, then:
696 # (d is the distinguishing argument index)
697 # 1. Let V be argi.
698 # Note: This is the argument that will be used to resolve which
699 # overload is selected.
700 cpp_value = 'info[%s]' % index
701
702 # Extract argument and IDL type to simplify accessing these in each loop.
703 arguments = [method['arguments'][index] for method in methods]
704 arguments_methods = zip(arguments, methods)
705 idl_types = [argument['idl_type_object'] for argument in arguments]
706 idl_types_methods = zip(idl_types, methods)
707
708 # We can’t do a single loop through all methods or simply sort them, because
709 # a method may be listed in multiple steps of the resolution algorithm, and
710 # which test to apply differs depending on the step.
711 #
712 # Instead, we need to go through all methods at each step, either finding
713 # first match (if only one test is allowed) or filtering to matches (if
714 # multiple tests are allowed), and generating an appropriate tests.
715
716 # 2. If V is undefined, and there is an entry in S whose list of
717 # optionality values has “optional” at index i, then remove from S all
718 # other entries.
719 try:
720 method = next(method for argument, method in arguments_methods
721 if argument['is_optional'])
722 test = '%s->IsUndefined()' % cpp_value
723 yield test, method
724 except StopIteration:
725 pass
726
727 # 3. Otherwise: if V is null or undefined, and there is an entry in S that
728 # has one of the following types at position i of its type list,
729 # • a nullable type
730 try:
731 method = next(method for idl_type, method in idl_types_methods
732 if idl_type.is_nullable)
733 test = 'isUndefinedOrNull(%s)' % cpp_value
734 yield test, method
735 except StopIteration:
736 pass
737
738 # 4. Otherwise: if V is a platform object – but not a platform array
739 # object – and there is an entry in S that has one of the following
740 # types at position i of its type list,
741 # • an interface type that V implements
742 # (Unlike most of these tests, this can return multiple methods, since we
743 # test if it implements an interface. Thus we need a for loop, not a next.)
744 # (We distinguish wrapper types from built-in interface types.)
745 for idl_type, method in ((idl_type, method)
746 for idl_type, method in idl_types_methods
747 if idl_type.is_wrapper_type):
748 test = 'V8{idl_type}::hasInstance({cpp_value}, info.GetIsolate())'.forma t(idl_type=idl_type.base_type, cpp_value=cpp_value)
749 yield test, method
750
751 # 8. Otherwise: if V is any kind of object except for a native Date object,
752 # a native RegExp object, and there is an entry in S that has one of the
753 # following types at position i of its type list,
754 # • an array type
755 # • a sequence type
756 # ...
757 # • a dictionary
758 try:
759 idl_type, method = next((idl_type, method)
760 for idl_type, method in idl_types_methods
761 if (idl_type.native_array_element_type or
762 idl_type.is_dictionary or
763 idl_type.name == 'Dictionary'))
764 if idl_type.native_array_element_type:
765 # (We test for Array instead of generic Object to type-check.)
766 # FIXME: test for Object during resolution, then have type check for
767 # Array in overloaded method: http://crbug.com/262383
768 test = '%s->IsArray()' % cpp_value
769 else:
770 # FIXME: should be '{1}->IsObject() && !{1}->IsDate() && !{1}->IsReg Exp()'.format(cpp_value)
771 # FIXME: the IsDate and IsRegExp checks can be skipped if we've
772 # already generated tests for them.
773 test = '%s->IsObject()' % cpp_value
774 yield test, method
775 except StopIteration:
776 pass
777
778 # (Check for exact type matches before performing automatic type conversion;
779 # only needed if distinguishing between primitive types.)
780 if len([idl_type.is_primitive_type for idl_type in idl_types]) > 1:
781 # (Only needed if match in step 11, otherwise redundant.)
782 if any(idl_type.is_string_type or idl_type.is_enum
783 for idl_type in idl_types):
784 # 10. Otherwise: if V is a Number value, and there is an entry in S
785 # that has one of the following types at position i of its type
786 # list,
787 # • a numeric type
788 try:
789 method = next(method for idl_type, method in idl_types_methods
790 if idl_type.is_numeric_type)
791 test = '%s->IsNumber()' % cpp_value
792 yield test, method
793 except StopIteration:
794 pass
795
796 # (Perform automatic type conversion, in order. If any of these match,
797 # that’s the end, and no other tests are needed.) To keep this code simple,
798 # we rely on the C++ compiler's dead code elimination to deal with the
799 # redundancy if both cases below trigger.
800
801 # 11. Otherwise: if there is an entry in S that has one of the following
802 # types at position i of its type list,
803 # • DOMString
804 # • ByteString
805 # • ScalarValueString [a DOMString typedef, per definition.]
806 # • an enumeration type
807 try:
808 method = next(method for idl_type, method in idl_types_methods
809 if idl_type.is_string_type or idl_type.is_enum)
810 yield 'true', method
811 except StopIteration:
812 pass
813
814 # 12. Otherwise: if there is an entry in S that has one of the following
815 # types at position i of its type list,
816 # • a numeric type
817 try:
818 method = next(method for idl_type, method in idl_types_methods
819 if idl_type.is_numeric_type)
820 yield 'true', method
821 except StopIteration:
822 pass
823
824
825 ################################################################################
826 # Utility functions
827 ################################################################################
828
829 def Counter(iterable):
830 # Once using Python 2.7, using collections.Counter
831 counter = defaultdict(lambda: 0)
832 for item in iterable:
833 counter[item] += 1
834 return counter
835
836
837 def common(dicts, f):
838 """Returns common result of f across an iterable of dicts, or None.
839
840 Call f for each dict and return its result if the same across all dicts.
841 """
842 values = (f(d) for d in dicts)
843 first_value = next(values)
844 if all(value == first_value for value in values):
845 return first_value
846 return None
847
848
849 def common_key(dicts, key):
850 """Returns common presence of a key across an iterable of dicts, or None.
851
852 True if all dicts have the key, False if none of the dicts have the key,
853 and None if some but not all dicts have the key.
854 """
855 return common(dicts, lambda d: key in d)
856
857
858 def common_value(dicts, key):
859 """Returns common value of a key across an iterable of dicts, or None.
860
861 Auxiliary function for overloads, so can consolidate an extended attribute
862 that appears with the same value on all items in an overload set.
863 """
864 return common(dicts, lambda d: d.get(key))
865
866
867 def sort_and_groupby(l, key=None):
868 """Returns a generator of (key, list), sorting and grouping list by key."""
869 l.sort(key=key)
870 return ((k, list(g)) for k, g in itertools.groupby(l, key))
871
872
873 ################################################################################
874 # Constructors
875 ################################################################################
876
877 # [Constructor]
878 def constructor_context(interface, constructor):
879 arguments_need_try_catch = any(v8_methods.argument_needs_try_catch(construct or, argument)
880 for argument in constructor.arguments)
881
882 # [RaisesException=Constructor]
883 is_constructor_raises_exception = \
884 interface.extended_attributes.get('RaisesException') == 'Constructor'
885
886 return {
887 'arguments': [v8_methods.argument_context(interface, constructor, argume nt, index)
888 for index, argument in enumerate(constructor.arguments)],
889 'arguments_need_try_catch': arguments_need_try_catch,
890 'cpp_type': cpp_template_type(
891 'RefPtr',
892 cpp_name(interface)),
893 'cpp_value': v8_methods.cpp_value(
894 interface, constructor, len(constructor.arguments)),
895 'has_exception_state':
896 is_constructor_raises_exception or
897 any(argument for argument in constructor.arguments
898 if argument.idl_type.name == 'SerializedScriptValue' or
899 argument.idl_type.may_raise_exception_on_conversion),
900 'is_call_with_document':
901 # [ConstructorCallWith=Document]
902 has_extended_attribute_value(interface,
903 'ConstructorCallWith', 'Document'),
904 'is_call_with_execution_context':
905 # [ConstructorCallWith=ExecutionContext]
906 has_extended_attribute_value(interface,
907 'ConstructorCallWith', 'ExecutionContext'),
908 'is_constructor': True,
909 'is_named_constructor': False,
910 'is_raises_exception': is_constructor_raises_exception,
911 'number_of_required_arguments':
912 number_of_required_arguments(constructor),
913 }
914
915
916 # [NamedConstructor]
917 def named_constructor_context(interface):
918 extended_attributes = interface.extended_attributes
919 if 'NamedConstructor' not in extended_attributes:
920 return None
921 # FIXME: parser should return named constructor separately;
922 # included in constructors (and only name stored in extended attribute)
923 # for Perl compatibility
924 idl_constructor = interface.constructors[-1]
925 assert idl_constructor.name == 'NamedConstructor'
926 context = constructor_context(interface, idl_constructor)
927 context.update({
928 'name': extended_attributes['NamedConstructor'],
929 'is_named_constructor': True,
930 })
931 return context
932
933
934 def number_of_required_arguments(constructor):
935 return len([argument for argument in constructor.arguments
936 if not argument.is_optional])
937
938
939 def interface_length(interface, constructors):
940 # Docs: http://heycam.github.io/webidl/#es-interface-call
941 if 'EventConstructor' in interface.extended_attributes:
942 return 1
943 if not constructors:
944 return 0
945 return min(constructor['number_of_required_arguments']
946 for constructor in constructors)
947
948
949 ################################################################################
950 # Special operations (methods)
951 # http://heycam.github.io/webidl/#idl-special-operations
952 ################################################################################
953
954 def property_getter(getter, cpp_arguments):
955 def is_null_expression(idl_type):
956 if idl_type.is_union_type:
957 notnull = ' || '.join([
958 member_argument['null_check_value']
959 for member_argument in idl_type.union_arguments])
960 return '!(%s)' % notnull
961 if idl_type.name == 'String':
962 return 'result.isNull()'
963 if idl_type.is_interface_type:
964 return '!result'
965 return ''
966
967 idl_type = getter.idl_type
968 extended_attributes = getter.extended_attributes
969 is_raises_exception = 'RaisesException' in extended_attributes
970
971 # FIXME: make more generic, so can use v8_methods.cpp_value
972 cpp_method_name = 'impl->%s' % cpp_name(getter)
973
974 if is_raises_exception:
975 cpp_arguments.append('exceptionState')
976 union_arguments = idl_type.union_arguments
977 if union_arguments:
978 cpp_arguments.extend([member_argument['cpp_value']
979 for member_argument in union_arguments])
980
981 cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments))
982
983 return {
984 'cpp_type': idl_type.cpp_type,
985 'cpp_value': cpp_value,
986 'is_custom':
987 'Custom' in extended_attributes and
988 (not extended_attributes['Custom'] or
989 has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')),
990 'is_custom_property_enumerator': has_extended_attribute_value(
991 getter, 'Custom', 'PropertyEnumerator'),
992 'is_custom_property_query': has_extended_attribute_value(
993 getter, 'Custom', 'PropertyQuery'),
994 'is_enumerable': 'NotEnumerable' not in extended_attributes,
995 'is_null_expression': is_null_expression(idl_type),
996 'is_raises_exception': is_raises_exception,
997 'name': cpp_name(getter),
998 'union_arguments': union_arguments,
999 'v8_set_return_value': idl_type.v8_set_return_value('result', extended_a ttributes=extended_attributes, script_wrappable='impl', release=idl_type.release ),
1000 }
1001
1002
1003 def property_setter(setter):
1004 idl_type = setter.arguments[1].idl_type
1005 extended_attributes = setter.extended_attributes
1006 is_raises_exception = 'RaisesException' in extended_attributes
1007 return {
1008 'has_type_checking_interface':
1009 has_extended_attribute_value(setter, 'TypeChecking', 'Interface') an d
1010 idl_type.is_wrapper_type,
1011 'idl_type': idl_type.base_type,
1012 'is_custom': 'Custom' in extended_attributes,
1013 'has_exception_state': is_raises_exception or
1014 idl_type.is_integer_type,
1015 'is_raises_exception': is_raises_exception,
1016 'name': cpp_name(setter),
1017 'v8_value_to_local_cpp_value': idl_type.v8_value_to_local_cpp_value(
1018 extended_attributes, 'v8Value', 'propertyValue'),
1019 }
1020
1021
1022 def property_deleter(deleter):
1023 idl_type = deleter.idl_type
1024 if str(idl_type) != 'boolean':
1025 raise Exception(
1026 'Only deleters with boolean type are allowed, but type is "%s"' %
1027 idl_type)
1028 extended_attributes = deleter.extended_attributes
1029 return {
1030 'is_custom': 'Custom' in extended_attributes,
1031 'is_raises_exception': 'RaisesException' in extended_attributes,
1032 'name': cpp_name(deleter),
1033 }
1034
1035
1036 ################################################################################
1037 # Indexed properties
1038 # http://heycam.github.io/webidl/#idl-indexed-properties
1039 ################################################################################
1040
1041 def indexed_property_getter(interface):
1042 try:
1043 # Find indexed property getter, if present; has form:
1044 # getter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1)
1045 getter = next(
1046 method
1047 for method in interface.operations
1048 if ('getter' in method.specials and
1049 len(method.arguments) == 1 and
1050 str(method.arguments[0].idl_type) == 'unsigned long'))
1051 except StopIteration:
1052 return None
1053
1054 return property_getter(getter, ['index'])
1055
1056
1057 def indexed_property_setter(interface):
1058 try:
1059 # Find indexed property setter, if present; has form:
1060 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE ARG2)
1061 setter = next(
1062 method
1063 for method in interface.operations
1064 if ('setter' in method.specials and
1065 len(method.arguments) == 2 and
1066 str(method.arguments[0].idl_type) == 'unsigned long'))
1067 except StopIteration:
1068 return None
1069
1070 return property_setter(setter)
1071
1072
1073 def indexed_property_deleter(interface):
1074 try:
1075 # Find indexed property deleter, if present; has form:
1076 # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG)
1077 deleter = next(
1078 method
1079 for method in interface.operations
1080 if ('deleter' in method.specials and
1081 len(method.arguments) == 1 and
1082 str(method.arguments[0].idl_type) == 'unsigned long'))
1083 except StopIteration:
1084 return None
1085
1086 return property_deleter(deleter)
1087
1088
1089 ################################################################################
1090 # Named properties
1091 # http://heycam.github.io/webidl/#idl-named-properties
1092 ################################################################################
1093
1094 def named_property_getter(interface):
1095 try:
1096 # Find named property getter, if present; has form:
1097 # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1)
1098 getter = next(
1099 method
1100 for method in interface.operations
1101 if ('getter' in method.specials and
1102 len(method.arguments) == 1 and
1103 str(method.arguments[0].idl_type) == 'DOMString'))
1104 except StopIteration:
1105 return None
1106
1107 getter.name = getter.name or 'anonymousNamedGetter'
1108 return property_getter(getter, ['propertyName'])
1109
1110
1111 def named_property_setter(interface):
1112 try:
1113 # Find named property setter, if present; has form:
1114 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2 )
1115 setter = next(
1116 method
1117 for method in interface.operations
1118 if ('setter' in method.specials and
1119 len(method.arguments) == 2 and
1120 str(method.arguments[0].idl_type) == 'DOMString'))
1121 except StopIteration:
1122 return None
1123
1124 return property_setter(setter)
1125
1126
1127 def named_property_deleter(interface):
1128 try:
1129 # Find named property deleter, if present; has form:
1130 # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG)
1131 deleter = next(
1132 method
1133 for method in interface.operations
1134 if ('deleter' in method.specials and
1135 len(method.arguments) == 1 and
1136 str(method.arguments[0].idl_type) == 'DOMString'))
1137 except StopIteration:
1138 return None
1139
1140 return property_deleter(deleter)
OLDNEW
« no previous file with comments | « sky/engine/bindings/scripts/v8_globals.py ('k') | sky/engine/bindings/scripts/v8_methods.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698