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

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

Issue 915293003: Rename sky/engine/bindings2 to sky/engine/bindings (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: more better 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/bindings2/scripts/v8_globals.py ('k') | sky/engine/bindings2/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, cpp_name,
50 has_extended_attribute_value,
51 extended_attribute_value_as_list)
52
53
54 INTERFACE_H_INCLUDES = frozenset([
55 'platform/heap/Handle.h',
56 ])
57
58 INTERFACE_CPP_INCLUDES = frozenset([
59 'sky/engine/bindings2/exception_state.h',
60 'core/dom/Document.h',
61 'base/trace_event/trace_event.h',
62 'wtf/GetPtr.h',
63 'wtf/RefPtr.h',
64 ])
65
66
67 def interface_context(interface):
68 includes.clear()
69 includes.update(INTERFACE_CPP_INCLUDES)
70 header_includes = set(INTERFACE_H_INCLUDES)
71
72 parent_interface = interface.parent
73 if parent_interface:
74 header_includes.update(v8_types.includes_for_interface(parent_interface) )
75 extended_attributes = interface.extended_attributes
76
77 # [ActiveDOMObject]
78 is_active_dom_object = 'ActiveDOMObject' in extended_attributes
79
80 # [DependentLifetime]
81 is_dependent_lifetime = 'DependentLifetime' in extended_attributes
82
83 # [Iterable]
84 iterator_method = None
85 if 'Iterable' in extended_attributes:
86 iterator_operation = IdlOperation(interface.idl_name)
87 iterator_operation.name = 'iterator'
88 iterator_operation.idl_type = IdlType('Iterator')
89 iterator_operation.extended_attributes['RaisesException'] = None
90 iterator_operation.extended_attributes['CallWith'] = 'ScriptState'
91 iterator_method = v8_methods.method_context(interface,
92 iterator_operation)
93
94 # [SetWrapperReferenceFrom]
95 reachable_node_function = extended_attributes.get('SetWrapperReferenceFrom')
96 if reachable_node_function:
97 includes.update(['core/dom/Element.h'])
98
99 # [SetWrapperReferenceTo]
100 set_wrapper_reference_to_list = [{
101 'name': argument.name,
102 # FIXME: properly should be:
103 # 'cpp_type': argument.idl_type.cpp_type_args(raw_type=True),
104 # (if type is non-wrapper type like NodeFilter, normally RefPtr)
105 # Raw pointers faster though, and NodeFilter hacky anyway.
106 'cpp_type': argument.idl_type.implemented_as + '*',
107 'idl_type': argument.idl_type,
108 } for argument in extended_attributes.get('SetWrapperReferenceTo', [])]
109 for set_wrapper_reference_to in set_wrapper_reference_to_list:
110 set_wrapper_reference_to['idl_type'].add_includes_for_type()
111
112 # [NotScriptWrappable]
113 is_script_wrappable = 'NotScriptWrappable' not in extended_attributes
114
115 # [SpecialWrapFor]
116 if 'SpecialWrapFor' in extended_attributes:
117 special_wrap_for = extended_attribute_value_as_list(interface, 'SpecialW rapFor')
118 else:
119 special_wrap_for = []
120 for special_wrap_interface in special_wrap_for:
121 v8_types.add_includes_for_interface(special_wrap_interface)
122
123 # [Custom=Wrap], [SetWrapperReferenceFrom]
124 has_visit_dom_wrapper = (
125 has_extended_attribute_value(interface, 'Custom', 'VisitDOMWrapper') or
126 reachable_node_function or
127 set_wrapper_reference_to_list)
128
129 wrapper_class_id = ('NodeClassId' if inherits_interface(interface.name, 'Nod e') else 'ObjectClassId')
130
131 context = {
132 'cpp_class': cpp_name(interface),
133 'has_custom_wrap': has_extended_attribute_value(interface, 'Custom', 'Wr ap'), # [Custom=Wrap]
134 'has_visit_dom_wrapper': has_visit_dom_wrapper,
135 'header_includes': header_includes,
136 'interface_name': interface.name,
137 'is_active_dom_object': is_active_dom_object,
138 'is_dependent_lifetime': is_dependent_lifetime,
139 'is_exception': interface.is_exception,
140 'is_script_wrappable': is_script_wrappable,
141 'iterator_method': iterator_method,
142 'lifetime': 'Dependent'
143 if (has_visit_dom_wrapper or
144 is_active_dom_object or
145 is_dependent_lifetime)
146 else 'Independent',
147 'parent_interface': parent_interface,
148 'reachable_node_function': reachable_node_function,
149 'set_wrapper_reference_to_list': set_wrapper_reference_to_list,
150 'special_wrap_for': special_wrap_for,
151 'wrapper_class_id': wrapper_class_id,
152 }
153
154 # Constructors
155 constructors = [constructor_context(interface, constructor)
156 for constructor in interface.constructors
157 # FIXME: shouldn't put named constructors with constructors
158 # (currently needed for Perl compatibility)
159 # Handle named constructors separately
160 if constructor.name == 'Constructor']
161 if len(constructors) > 1:
162 context['constructor_overloads'] = overloads_context(constructors)
163
164 # [CustomConstructor]
165 custom_constructors = [{ # Only needed for computing interface length
166 'number_of_required_arguments':
167 number_of_required_arguments(constructor),
168 } for constructor in interface.custom_constructors]
169
170 # [EventConstructor]
171 has_event_constructor = 'EventConstructor' in extended_attributes
172 any_type_attributes = [attribute for attribute in interface.attributes
173 if attribute.idl_type.name == 'Any']
174
175 # [NamedConstructor]
176 named_constructor = named_constructor_context(interface)
177
178 if (constructors or custom_constructors or has_event_constructor or
179 named_constructor):
180 includes.add('core/frame/LocalDOMWindow.h')
181
182 context.update({
183 'any_type_attributes': any_type_attributes,
184 'constructors': constructors,
185 'has_custom_constructor': bool(custom_constructors),
186 'has_event_constructor': has_event_constructor,
187 'interface_length':
188 interface_length(interface, constructors + custom_constructors),
189 'is_constructor_raises_exception': extended_attributes.get('RaisesExcept ion') == 'Constructor', # [RaisesException=Constructor]
190 'named_constructor': named_constructor,
191 })
192
193 constants = [constant_context(constant) for constant in interface.constants]
194
195 # Constants
196 context.update({
197 'constants': constants,
198 'has_constant_configuration': True,
199 })
200
201 # Attributes
202 attributes = [v8_attributes.attribute_context(interface, attribute)
203 for attribute in interface.attributes]
204 context.update({
205 'attributes': attributes,
206 'has_conditional_attributes': any(attribute['exposed_test'] for attribut e in attributes),
207 'has_constructor_attributes': any(attribute['constructor_type'] for attr ibute in attributes),
208 'has_replaceable_attributes': any(attribute['is_replaceable'] for attrib ute in attributes),
209 })
210
211 # Methods
212 methods = [v8_methods.method_context(interface, method)
213 for method in interface.operations
214 if method.name] # Skip anonymous special operations (methods)
215 compute_method_overloads_context(methods)
216
217 # Stringifier
218 if interface.stringifier:
219 stringifier = interface.stringifier
220 method = IdlOperation(interface.idl_name)
221 method.name = 'toString'
222 method.idl_type = IdlType('DOMString')
223 method.extended_attributes.update(stringifier.extended_attributes)
224 if stringifier.attribute:
225 method.extended_attributes['ImplementedAs'] = stringifier.attribute. name
226 elif stringifier.operation:
227 method.extended_attributes['ImplementedAs'] = stringifier.operation. name
228 methods.append(v8_methods.method_context(interface, method))
229
230 conditionally_enabled_methods = []
231 custom_registration_methods = []
232 method_configuration_methods = []
233
234 for method in methods:
235 # Skip all but one method in each set of overloaded methods.
236 if 'overload_index' in method and 'overloads' not in method:
237 continue
238
239 if 'overloads' in method:
240 overloads = method['overloads']
241 conditionally_exposed_function = overloads['exposed_test_all']
242 has_custom_registration = overloads['has_custom_registration_all']
243 else:
244 conditionally_exposed_function = method['exposed_test']
245 has_custom_registration = method['has_custom_registration']
246
247 if conditionally_exposed_function:
248 conditionally_enabled_methods.append(method)
249 continue
250 if has_custom_registration:
251 custom_registration_methods.append(method)
252 continue
253 method_configuration_methods.append(method)
254
255 for method in methods:
256 # The value of the Function object’s “length” property is a Number
257 # determined as follows:
258 # 1. Let S be the effective overload set for regular operations (if the
259 # operation is a regular operation) or for static operations (if the
260 # operation is a static operation) with identifier id on interface I and
261 # with argument count 0.
262 # 2. Return the length of the shortest argument list of the entries in S .
263 # FIXME: This calculation doesn't take into account whether runtime
264 # enabled overloads are actually enabled, so length may be incorrect.
265 # E.g., [RuntimeEnabled=Foo] void f(); void f(long x);
266 # should have length 1 if Foo is not enabled, but length 0 if it is.
267 method['length'] = (method['overloads']['minarg'] if 'overloads' in meth od else
268 method['number_of_required_arguments'])
269
270 context.update({
271 'conditionally_enabled_methods': conditionally_enabled_methods,
272 'custom_registration_methods': custom_registration_methods,
273 'method_configuration_methods': method_configuration_methods,
274 'methods': methods,
275 })
276
277 context.update({
278 'indexed_property_getter': indexed_property_getter(interface),
279 'indexed_property_setter': indexed_property_setter(interface),
280 'indexed_property_deleter': indexed_property_deleter(interface),
281 'is_override_builtins': 'OverrideBuiltins' in extended_attributes,
282 'named_property_getter': named_property_getter(interface),
283 'named_property_setter': named_property_setter(interface),
284 'named_property_deleter': named_property_deleter(interface),
285 })
286
287 return context
288
289
290 # [DeprecateAs], [Reflect]
291 def constant_context(constant):
292 # (Blink-only) string literals are unquoted in tokenizer, must be re-quoted
293 # in C++.
294 if constant.idl_type.name == 'String':
295 value = '"%s"' % constant.value
296 else:
297 value = constant.value
298
299 extended_attributes = constant.extended_attributes
300 return {
301 'cpp_class': extended_attributes.get('PartialInterfaceImplementedAs'),
302 'idl_type': constant.idl_type.name,
303 'name': constant.name,
304 # FIXME: use 'reflected_name' as correct 'name'
305 'reflected_name': extended_attributes.get('Reflect', constant.name),
306 'value': value,
307 }
308
309
310 ################################################################################
311 # Overloads
312 ################################################################################
313
314 def compute_method_overloads_context(methods):
315 # Regular methods
316 compute_method_overloads_context_by_type([method for method in methods
317 if not method['is_static']])
318 # Static methods
319 compute_method_overloads_context_by_type([method for method in methods
320 if method['is_static']])
321
322
323 def compute_method_overloads_context_by_type(methods):
324 """Computes |method.overload*| template values.
325
326 Called separately for static and non-static (regular) methods,
327 as these are overloaded separately.
328 Modifies |method| in place for |method| in |methods|.
329 Doesn't change the |methods| list itself (only the values, i.e. individual
330 methods), so ok to treat these separately.
331 """
332 # Add overload information only to overloaded methods, so template code can
333 # easily verify if a function is overloaded
334 for name, overloads in method_overloads_by_name(methods):
335 # Resolution function is generated after last overloaded function;
336 # package necessary information into |method.overloads| for that method.
337 overloads[-1]['overloads'] = overloads_context(overloads)
338 overloads[-1]['overloads']['name'] = name
339
340
341 def method_overloads_by_name(methods):
342 """Returns generator of overloaded methods by name: [name, [method]]"""
343 # Filter to only methods that are actually overloaded
344 method_counts = Counter(method['name'] for method in methods)
345 overloaded_method_names = set(name
346 for name, count in method_counts.iteritems()
347 if count > 1)
348 overloaded_methods = [method for method in methods
349 if method['name'] in overloaded_method_names]
350
351 # Group by name (generally will be defined together, but not necessarily)
352 return sort_and_groupby(overloaded_methods, itemgetter('name'))
353
354
355 def overloads_context(overloads):
356 """Returns |overloads| template values for a single name.
357
358 Sets |method.overload_index| in place for |method| in |overloads|
359 and returns dict of overall overload template values.
360 """
361 assert len(overloads) > 1 # only apply to overloaded names
362 for index, method in enumerate(overloads, 1):
363 method['overload_index'] = index
364
365 effective_overloads_by_length = effective_overload_set_by_length(overloads)
366 lengths = [length for length, _ in effective_overloads_by_length]
367 name = overloads[0].get('name', '<constructor>')
368
369 # Check and fail if all overloads with the shortest acceptable arguments
370 # list are runtime enabled, since we would otherwise set 'length' on the
371 # function object to an incorrect value when none of those overloads were
372 # actually enabled at runtime. The exception is if all overloads are
373 # controlled by the same runtime enabled feature, in which case there would
374 # be no function object at all if it is not enabled.
375 shortest_overloads = effective_overloads_by_length[0][1]
376
377 # Check and fail if overloads disagree on any of the extended attributes
378 # that affect how the method should be registered.
379 # Skip the check for overloaded constructors, since they don't support any
380 # of the extended attributes in question.
381 if not overloads[0].get('is_constructor'):
382 overload_extended_attributes = [
383 method['custom_registration_extended_attributes']
384 for method in overloads]
385 for extended_attribute in v8_methods.CUSTOM_REGISTRATION_EXTENDED_ATTRIB UTES:
386 if common_key(overload_extended_attributes, extended_attribute) is N one:
387 raise ValueError('Overloads of %s have conflicting extended attr ibute %s'
388 % (name, extended_attribute))
389
390 # Check and fail if overloads disagree about whether the return type
391 # is a Promise or not.
392 promise_overload_count = sum(1 for method in overloads if method.get('idl_ty pe') == 'Promise')
393 if promise_overload_count not in (0, len(overloads)):
394 raise ValueError('Overloads of %s have conflicting Promise/non-Promise t ypes'
395 % (name))
396
397 return {
398 'exposed_test_all': common_value(overloads, 'exposed_test'), # [Exposed ]
399 'has_custom_registration_all': common_value(overloads, 'has_custom_regis tration'),
400 # 1. Let maxarg be the length of the longest type list of the
401 # entries in S.
402 'maxarg': lengths[-1],
403 'minarg': lengths[0],
404 'valid_arities': lengths
405 # Only need to report valid arities if there is a gap in the
406 # sequence of possible lengths, otherwise invalid length means
407 # "not enough arguments".
408 if lengths[-1] - lengths[0] != len(lengths) - 1 else None,
409 }
410
411
412 def effective_overload_set(F):
413 """Returns the effective overload set of an overloaded function.
414
415 An effective overload set is the set of overloaded functions + signatures
416 (type list of arguments, with optional and variadic arguments included or
417 not), and is used in the overload resolution algorithm.
418
419 For example, given input [f1(optional long x), f2(DOMString s)], the output
420 is informally [f1(), f1(long), f2(DOMString)], and formally
421 [(f1, [], []), (f1, [long], [optional]), (f2, [DOMString], [required])].
422
423 Currently the optionality list is a list of |is_optional| booleans (True
424 means optional, False means required); to support variadics this needs to
425 be tri-valued as required, optional, or variadic.
426
427 Formally:
428 An effective overload set represents the allowable invocations for a
429 particular operation, constructor (specified with [Constructor] or
430 [NamedConstructor]), legacy caller or callback function.
431
432 An additional argument N (argument count) is needed when overloading
433 variadics, but we don't use that currently.
434
435 Spec: http://heycam.github.io/webidl/#dfn-effective-overload-set
436
437 Formally the input and output lists are sets, but methods are stored
438 internally as dicts, which can't be stored in a set because they are not
439 hashable, so we use lists instead.
440
441 Arguments:
442 F: list of overloads for a given callable name.
443
444 Returns:
445 S: list of tuples of the form (callable, type list, optionality list).
446 """
447 # Code closely follows the algorithm in the spec, for clarity and
448 # correctness, and hence is not very Pythonic.
449
450 # 1. Initialize S to ∅.
451 # (We use a list because we can't use a set, as noted above.)
452 S = []
453
454 # 2. Let F be a set with elements as follows, according to the kind of
455 # effective overload set:
456 # (Passed as argument, nothing to do.)
457
458 # 3. & 4. (maxarg, m) are only needed for variadics, not used.
459
460 # 5. For each operation, extended attribute or callback function X in F:
461 for X in F: # X is the "callable", F is the overloads.
462 arguments = X['arguments']
463 # 1. Let n be the number of arguments X is declared to take.
464 n = len(arguments)
465 # 2. Let t0..n−1 be a list of types, where ti is the type of X’s
466 # argument at index i.
467 # (“type list”)
468 t = tuple(argument['idl_type_object'] for argument in arguments)
469 # 3. Let o0..n−1 be a list of optionality values, where oi is “variadic”
470 # if X’s argument at index i is a final, variadic argument, “optional”
471 # if the argument is optional, and “required” otherwise.
472 # (“optionality list”)
473 # (We’re just using a boolean for optional vs. required.)
474 o = tuple(argument['is_optional'] for argument in arguments)
475 # 4. Add to S the tuple <X, t0..n−1, o0..n−1>.
476 S.append((X, t, o))
477 # 5. If X is declared to be variadic, then:
478 # (Not used, so not implemented.)
479 # 6. Initialize i to n−1.
480 i = n - 1
481 # 7. While i ≥ 0:
482 # Spec bug (fencepost error); should be “While i > 0:”
483 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=25590
484 while i > 0:
485 # 1. If argument i of X is not optional, then break this loop.
486 if not o[i]:
487 break
488 # 2. Otherwise, add to S the tuple <X, t0..i−1, o0..i−1>.
489 S.append((X, t[:i], o[:i]))
490 # 3. Set i to i−1.
491 i = i - 1
492 # 8. If n > 0 and all arguments of X are optional, then add to S the
493 # tuple <X, (), ()> (where “()” represents the empty list).
494 if n > 0 and all(oi for oi in o):
495 S.append((X, [], []))
496 # 6. The effective overload set is S.
497 return S
498
499
500 def effective_overload_set_by_length(overloads):
501 def type_list_length(entry):
502 # Entries in the effective overload set are 3-tuples:
503 # (callable, type list, optionality list)
504 return len(entry[1])
505
506 effective_overloads = effective_overload_set(overloads)
507 return list(sort_and_groupby(effective_overloads, type_list_length))
508
509
510 def distinguishing_argument_index(entries):
511 """Returns the distinguishing argument index for a sequence of entries.
512
513 Entries are elements of the effective overload set with the same number
514 of arguments (formally, same type list length), each a 3-tuple of the form
515 (callable, type list, optionality list).
516
517 Spec: http://heycam.github.io/webidl/#dfn-distinguishing-argument-index
518
519 If there is more than one entry in an effective overload set that has a
520 given type list length, then for those entries there must be an index i
521 such that for each pair of entries the types at index i are
522 distinguishable.
523 The lowest such index is termed the distinguishing argument index for the
524 entries of the effective overload set with the given type list length.
525 """
526 # Only applicable “If there is more than one entry”
527 assert len(entries) > 1
528 type_lists = [tuple(idl_type.name for idl_type in entry[1])
529 for entry in entries]
530 type_list_length = len(type_lists[0])
531 # Only applicable for entries that “[have] a given type list length”
532 assert all(len(type_list) == type_list_length for type_list in type_lists)
533 name = entries[0][0].get('name', 'Constructor') # for error reporting
534
535 # The spec defines the distinguishing argument index by conditions it must
536 # satisfy, but does not give an algorithm.
537 #
538 # We compute the distinguishing argument index by first computing the
539 # minimum index where not all types are the same, and then checking that
540 # all types in this position are distinguishable (and the optionality lists
541 # up to this point are identical), since "minimum index where not all types
542 # are the same" is a *necessary* condition, and more direct to check than
543 # distinguishability.
544 types_by_index = (set(types) for types in zip(*type_lists))
545 try:
546 # “In addition, for each index j, where j is less than the
547 # distinguishing argument index for a given type list length, the types
548 # at index j in all of the entries’ type lists must be the same”
549 index = next(i for i, types in enumerate(types_by_index)
550 if len(types) > 1)
551 except StopIteration:
552 raise ValueError('No distinguishing index found for %s, length %s:\n'
553 'All entries have the same type list:\n'
554 '%s' % (name, type_list_length, type_lists[0]))
555 # Check optionality
556 # “and the booleans in the corresponding list indicating argument
557 # optionality must be the same.”
558 # FIXME: spec typo: optionality value is no longer a boolean
559 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=25628
560 initial_optionality_lists = set(entry[2][:index] for entry in entries)
561 if len(initial_optionality_lists) > 1:
562 raise ValueError(
563 'Invalid optionality lists for %s, length %s:\n'
564 'Optionality lists differ below distinguishing argument index %s:\n'
565 '%s'
566 % (name, type_list_length, index, set(initial_optionality_lists)))
567
568 # Check distinguishability
569 # http://heycam.github.io/webidl/#dfn-distinguishable
570 # Use names to check for distinct types, since objects are distinct
571 # FIXME: check distinguishability more precisely, for validation
572 distinguishing_argument_type_names = [type_list[index]
573 for type_list in type_lists]
574 if (len(set(distinguishing_argument_type_names)) !=
575 len(distinguishing_argument_type_names)):
576 raise ValueError('Types in distinguishing argument are not distinct:\n'
577 '%s' % distinguishing_argument_type_names)
578
579 return index
580
581
582 ################################################################################
583 # Utility functions
584 ################################################################################
585
586 def Counter(iterable):
587 # Once using Python 2.7, using collections.Counter
588 counter = defaultdict(lambda: 0)
589 for item in iterable:
590 counter[item] += 1
591 return counter
592
593
594 def common(dicts, f):
595 """Returns common result of f across an iterable of dicts, or None.
596
597 Call f for each dict and return its result if the same across all dicts.
598 """
599 values = (f(d) for d in dicts)
600 first_value = next(values)
601 if all(value == first_value for value in values):
602 return first_value
603 return None
604
605
606 def common_key(dicts, key):
607 """Returns common presence of a key across an iterable of dicts, or None.
608
609 True if all dicts have the key, False if none of the dicts have the key,
610 and None if some but not all dicts have the key.
611 """
612 return common(dicts, lambda d: key in d)
613
614
615 def common_value(dicts, key):
616 """Returns common value of a key across an iterable of dicts, or None.
617
618 Auxiliary function for overloads, so can consolidate an extended attribute
619 that appears with the same value on all items in an overload set.
620 """
621 return common(dicts, lambda d: d.get(key))
622
623
624 def sort_and_groupby(l, key=None):
625 """Returns a generator of (key, list), sorting and grouping list by key."""
626 l.sort(key=key)
627 return ((k, list(g)) for k, g in itertools.groupby(l, key))
628
629
630 ################################################################################
631 # Constructors
632 ################################################################################
633
634 # [Constructor]
635 def constructor_context(interface, constructor):
636 arguments_need_try_catch = any(v8_methods.argument_needs_try_catch(construct or, argument)
637 for argument in constructor.arguments)
638
639 # [RaisesException=Constructor]
640 is_constructor_raises_exception = \
641 interface.extended_attributes.get('RaisesException') == 'Constructor'
642
643 return {
644 'arguments': [v8_methods.argument_context(interface, constructor, argume nt, index)
645 for index, argument in enumerate(constructor.arguments)],
646 'arguments_need_try_catch': arguments_need_try_catch,
647 'cpp_type': cpp_template_type(
648 'RefPtr',
649 cpp_name(interface)),
650 'cpp_value': v8_methods.cpp_value(
651 interface, constructor, len(constructor.arguments)),
652 'has_exception_state':
653 is_constructor_raises_exception or
654 any(argument for argument in constructor.arguments
655 if argument.idl_type.name == 'SerializedScriptValue' or
656 argument.idl_type.may_raise_exception_on_conversion),
657 'is_call_with_document':
658 # [ConstructorCallWith=Document]
659 has_extended_attribute_value(interface,
660 'ConstructorCallWith', 'Document'),
661 'is_call_with_execution_context':
662 # [ConstructorCallWith=ExecutionContext]
663 has_extended_attribute_value(interface,
664 'ConstructorCallWith', 'ExecutionContext'),
665 'is_constructor': True,
666 'is_named_constructor': False,
667 'is_raises_exception': is_constructor_raises_exception,
668 'number_of_required_arguments':
669 number_of_required_arguments(constructor),
670 }
671
672
673 # [NamedConstructor]
674 def named_constructor_context(interface):
675 extended_attributes = interface.extended_attributes
676 if 'NamedConstructor' not in extended_attributes:
677 return None
678 # FIXME: parser should return named constructor separately;
679 # included in constructors (and only name stored in extended attribute)
680 # for Perl compatibility
681 idl_constructor = interface.constructors[-1]
682 assert idl_constructor.name == 'NamedConstructor'
683 context = constructor_context(interface, idl_constructor)
684 context.update({
685 'name': extended_attributes['NamedConstructor'],
686 'is_named_constructor': True,
687 })
688 return context
689
690
691 def number_of_required_arguments(constructor):
692 return len([argument for argument in constructor.arguments
693 if not argument.is_optional])
694
695
696 def interface_length(interface, constructors):
697 # Docs: http://heycam.github.io/webidl/#es-interface-call
698 if 'EventConstructor' in interface.extended_attributes:
699 return 1
700 if not constructors:
701 return 0
702 return min(constructor['number_of_required_arguments']
703 for constructor in constructors)
704
705
706 ################################################################################
707 # Special operations (methods)
708 # http://heycam.github.io/webidl/#idl-special-operations
709 ################################################################################
710
711 def property_getter(getter, cpp_arguments):
712 def is_null_expression(idl_type):
713 if idl_type.is_union_type:
714 notnull = ' || '.join([
715 member_argument['null_check_value']
716 for member_argument in idl_type.union_arguments])
717 return '!(%s)' % notnull
718 if idl_type.name == 'String':
719 return 'result.isNull()'
720 if idl_type.is_interface_type:
721 return '!result'
722 return ''
723
724 idl_type = getter.idl_type
725 extended_attributes = getter.extended_attributes
726 is_raises_exception = 'RaisesException' in extended_attributes
727
728 # FIXME: make more generic, so can use v8_methods.cpp_value
729 cpp_method_name = 'impl->%s' % cpp_name(getter)
730
731 if is_raises_exception:
732 cpp_arguments.append('exceptionState')
733 union_arguments = idl_type.union_arguments
734 if union_arguments:
735 cpp_arguments.extend([member_argument['cpp_value']
736 for member_argument in union_arguments])
737
738 cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments))
739
740 return {
741 'cpp_type': idl_type.cpp_type,
742 'cpp_value': cpp_value,
743 'is_custom':
744 'Custom' in extended_attributes and
745 (not extended_attributes['Custom'] or
746 has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')),
747 'is_custom_property_enumerator': has_extended_attribute_value(
748 getter, 'Custom', 'PropertyEnumerator'),
749 'is_custom_property_query': has_extended_attribute_value(
750 getter, 'Custom', 'PropertyQuery'),
751 'is_enumerable': 'NotEnumerable' not in extended_attributes,
752 'is_null_expression': is_null_expression(idl_type),
753 'is_raises_exception': is_raises_exception,
754 'name': cpp_name(getter),
755 'union_arguments': union_arguments,
756 }
757
758
759 def property_setter(setter):
760 idl_type = setter.arguments[1].idl_type
761 extended_attributes = setter.extended_attributes
762 is_raises_exception = 'RaisesException' in extended_attributes
763 return {
764 'has_type_checking_interface':
765 has_extended_attribute_value(setter, 'TypeChecking', 'Interface') an d
766 idl_type.is_wrapper_type,
767 'idl_type': idl_type.base_type,
768 'is_custom': 'Custom' in extended_attributes,
769 'has_exception_state': is_raises_exception or
770 idl_type.is_integer_type,
771 'is_raises_exception': is_raises_exception,
772 'name': cpp_name(setter),
773 }
774
775
776 def property_deleter(deleter):
777 idl_type = deleter.idl_type
778 if str(idl_type) != 'boolean':
779 raise Exception(
780 'Only deleters with boolean type are allowed, but type is "%s"' %
781 idl_type)
782 extended_attributes = deleter.extended_attributes
783 return {
784 'is_custom': 'Custom' in extended_attributes,
785 'is_raises_exception': 'RaisesException' in extended_attributes,
786 'name': cpp_name(deleter),
787 }
788
789
790 ################################################################################
791 # Indexed properties
792 # http://heycam.github.io/webidl/#idl-indexed-properties
793 ################################################################################
794
795 def indexed_property_getter(interface):
796 try:
797 # Find indexed property getter, if present; has form:
798 # getter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1)
799 getter = next(
800 method
801 for method in interface.operations
802 if ('getter' in method.specials and
803 len(method.arguments) == 1 and
804 str(method.arguments[0].idl_type) == 'unsigned long'))
805 except StopIteration:
806 return None
807
808 return property_getter(getter, ['index'])
809
810
811 def indexed_property_setter(interface):
812 try:
813 # Find indexed property setter, if present; has form:
814 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE ARG2)
815 setter = next(
816 method
817 for method in interface.operations
818 if ('setter' in method.specials and
819 len(method.arguments) == 2 and
820 str(method.arguments[0].idl_type) == 'unsigned long'))
821 except StopIteration:
822 return None
823
824 return property_setter(setter)
825
826
827 def indexed_property_deleter(interface):
828 try:
829 # Find indexed property deleter, if present; has form:
830 # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG)
831 deleter = next(
832 method
833 for method in interface.operations
834 if ('deleter' in method.specials and
835 len(method.arguments) == 1 and
836 str(method.arguments[0].idl_type) == 'unsigned long'))
837 except StopIteration:
838 return None
839
840 return property_deleter(deleter)
841
842
843 ################################################################################
844 # Named properties
845 # http://heycam.github.io/webidl/#idl-named-properties
846 ################################################################################
847
848 def named_property_getter(interface):
849 try:
850 # Find named property getter, if present; has form:
851 # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1)
852 getter = next(
853 method
854 for method in interface.operations
855 if ('getter' in method.specials and
856 len(method.arguments) == 1 and
857 str(method.arguments[0].idl_type) == 'DOMString'))
858 except StopIteration:
859 return None
860
861 getter.name = getter.name or 'anonymousNamedGetter'
862 return property_getter(getter, ['propertyName'])
863
864
865 def named_property_setter(interface):
866 try:
867 # Find named property setter, if present; has form:
868 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2 )
869 setter = next(
870 method
871 for method in interface.operations
872 if ('setter' in method.specials and
873 len(method.arguments) == 2 and
874 str(method.arguments[0].idl_type) == 'DOMString'))
875 except StopIteration:
876 return None
877
878 return property_setter(setter)
879
880
881 def named_property_deleter(interface):
882 try:
883 # Find named property deleter, if present; has form:
884 # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG)
885 deleter = next(
886 method
887 for method in interface.operations
888 if ('deleter' in method.specials and
889 len(method.arguments) == 1 and
890 str(method.arguments[0].idl_type) == 'DOMString'))
891 except StopIteration:
892 return None
893
894 return property_deleter(deleter)
OLDNEW
« no previous file with comments | « sky/engine/bindings2/scripts/v8_globals.py ('k') | sky/engine/bindings2/scripts/v8_methods.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698