OLD | NEW |
1 # Copyright (C) 2013 Google Inc. All rights reserved. | 1 # Copyright (C) 2013 Google Inc. All rights reserved. |
| 2 # coding=utf-8 |
2 # | 3 # |
3 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
4 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
5 # met: | 6 # met: |
6 # | 7 # |
7 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
8 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
9 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
10 # copyright notice, this list of conditions and the following disclaimer | 11 # copyright notice, this list of conditions and the following disclaimer |
11 # in the documentation and/or other materials provided with the | 12 # in the documentation and/or other materials provided with the |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 | 330 |
330 # Group by name (generally will be defined together, but not necessarily) | 331 # Group by name (generally will be defined together, but not necessarily) |
331 overloaded_methods.sort(key=itemgetter('name')) | 332 overloaded_methods.sort(key=itemgetter('name')) |
332 method_overloads = dict( | 333 method_overloads = dict( |
333 (name, list(methods_iterator)) for name, methods_iterator in | 334 (name, list(methods_iterator)) for name, methods_iterator in |
334 itertools.groupby(overloaded_methods, itemgetter('name'))) | 335 itertools.groupby(overloaded_methods, itemgetter('name'))) |
335 | 336 |
336 # Add overload information only to overloaded methods, so template code can | 337 # Add overload information only to overloaded methods, so template code can |
337 # easily verify if a function is overloaded | 338 # easily verify if a function is overloaded |
338 for name, overloads in method_overloads.iteritems(): | 339 for name, overloads in method_overloads.iteritems(): |
| 340 effective_overload_set(overloads) # to test, compute but discard result |
339 for index, method in enumerate(overloads, 1): | 341 for index, method in enumerate(overloads, 1): |
340 method.update({ | 342 method.update({ |
341 'overload_index': index, | 343 'overload_index': index, |
342 'overload_resolution_expression': | 344 'overload_resolution_expression': |
343 overload_resolution_expression(method), | 345 overload_resolution_expression(method), |
344 }) | 346 }) |
345 | 347 |
346 # Resolution function is generated after last overloaded function; | 348 # Resolution function is generated after last overloaded function; |
347 # package necessary information into |method.overloads| for that method. | 349 # package necessary information into |method.overloads| for that method. |
348 minimum_number_of_required_arguments = min( | 350 minimum_number_of_required_arguments = min( |
349 method['number_of_required_arguments'] for method in overloads) | 351 method['number_of_required_arguments'] for method in overloads) |
350 overloads[-1]['overloads'] = { | 352 overloads[-1]['overloads'] = { |
351 'has_exception_state': bool(minimum_number_of_required_arguments), | 353 'has_exception_state': bool(minimum_number_of_required_arguments), |
352 'methods': overloads, | 354 'methods': overloads, |
353 'minimum_number_of_required_arguments': minimum_number_of_required_a
rguments, | 355 'minimum_number_of_required_arguments': minimum_number_of_required_a
rguments, |
354 'name': name, | 356 'name': name, |
355 'measure_all_as': common_value(overloads, 'measure_as'), # [Measure
As] | 357 'measure_all_as': common_value(overloads, 'measure_as'), # [Measure
As] |
356 'deprecate_all_as': common_value(overloads, 'deprecate_as'), # [Dep
recateAs] | 358 'deprecate_all_as': common_value(overloads, 'deprecate_as'), # [Dep
recateAs] |
357 } | 359 } |
358 | 360 |
359 | 361 |
| 362 def effective_overload_set(F): |
| 363 """Returns the effective overload set of an overloaded function. |
| 364 |
| 365 An effective overload set is the set of overloaded functions + signatures |
| 366 (type list of arguments, with optional and variadic arguments included or |
| 367 not), and is used in the overload resolution algorithm. |
| 368 |
| 369 For example, given input [f1(optional long x), f2(DOMString s)], the output |
| 370 is informally [f1(), f1(long), f2(DOMString)], and formally |
| 371 [(f1, [], []), (f1, [long], [optional]), (f2, [DOMString], [required])]. |
| 372 |
| 373 Currently the optionality list is a list of |is_optional| booleans (True |
| 374 means optional, False means required); to support variadics this needs to |
| 375 be tri-valued as required, optional, or variadic. |
| 376 |
| 377 Formally: |
| 378 An effective overload set represents the allowable invocations for a |
| 379 particular operation, constructor (specified with [Constructor] or |
| 380 [NamedConstructor]), legacy caller or callback function. |
| 381 |
| 382 An additional argument N (argument count) is needed when overloading |
| 383 variadics, but we don't use that currently. |
| 384 |
| 385 Spec: http://heycam.github.io/webidl/#dfn-effective-overload-set |
| 386 |
| 387 Formally the input and output lists are sets, but methods are stored |
| 388 internally as dicts, which can't be stored in a set because they are not |
| 389 hashable, so we use lists instead. |
| 390 |
| 391 Arguments: |
| 392 F: list of overloads for a given callable name. |
| 393 |
| 394 Returns: |
| 395 S: list of tuples of the form <callable, type list, optionality list>. |
| 396 """ |
| 397 # Code closely follows the algorithm in the spec, for clarity and |
| 398 # correctness, and hence is not very Pythonic. |
| 399 |
| 400 # 1. Initialize S to ∅. |
| 401 # (We use a list because we can't use a set, as noted above.) |
| 402 S = [] |
| 403 |
| 404 # 2. Let F be a set with elements as follows, according to the kind of |
| 405 # effective overload set: |
| 406 # (Passed as argument, nothing to do.) |
| 407 |
| 408 # 3. & 4. (maxarg, m) are only needed for variadics, not used. |
| 409 |
| 410 # 5. For each operation, extended attribute or callback function X in F: |
| 411 for X in F: # X is the "callable", F is the overloads. |
| 412 arguments = X['arguments'] |
| 413 # 1. Let n be the number of arguments X is declared to take. |
| 414 n = len(arguments) |
| 415 # 2. Let t0..n−1 be a list of types, where ti is the type of X’s |
| 416 # argument at index i. |
| 417 t = [argument['idl_type'] for argument in arguments] # type list |
| 418 # 3. Let o0..n−1 be a list of optionality values, where oi is “variadic” |
| 419 # if X’s argument at index i is a final, variadic argument, “optional” |
| 420 # if the argument is optional, and “required” otherwise. |
| 421 # (We're just using a boolean for optional vs. required.) |
| 422 o = [argument['is_optional'] for argument in arguments] # optionality l
ist |
| 423 # 4. Add to S the tuple <X, t0..n−1, o0..n−1>. |
| 424 S.append((X, t, o)) |
| 425 # 5. If X is declared to be variadic, then: |
| 426 # (Not used, so not implemented.) |
| 427 # 6. Initialize i to n−1. |
| 428 i = n - 1 |
| 429 # 7. While i ≥ 0: |
| 430 # Spec bug (fencepost error); should be “While i > 0:” |
| 431 # https://www.w3.org/Bugs/Public/show_bug.cgi?id=25590 |
| 432 while i > 0: |
| 433 # 1. If argument i of X is not optional, then break this loop. |
| 434 if not o[i]: |
| 435 break |
| 436 # 2. Otherwise, add to S the tuple <X, t0..i−1, o0..i−1>. |
| 437 S.append((X, t[:i], o[:i])) |
| 438 # 3. Set i to i−1. |
| 439 i = i - 1 |
| 440 # 8. If n > 0 and all arguments of X are optional, then add to S the |
| 441 # tuple <X, (), ()> (where “()” represents the empty list). |
| 442 if n > 0 and all(oi for oi in o): |
| 443 S.append((X, [], [])) |
| 444 # 6. The effective overload set is S. |
| 445 return S |
| 446 |
| 447 |
360 def overload_resolution_expression(method): | 448 def overload_resolution_expression(method): |
361 # Expression is an OR of ANDs: each term in the OR corresponds to a | 449 # Expression is an OR of ANDs: each term in the OR corresponds to a |
362 # possible argument count for a given method, with type checks. | 450 # possible argument count for a given method, with type checks. |
363 # FIXME: Blink's overload resolution algorithm is incorrect, per: | 451 # FIXME: Blink's overload resolution algorithm is incorrect, per: |
364 # Implement WebIDL overload resolution algorithm. http://crbug.com/293561 | 452 # Implement WebIDL overload resolution algorithm. http://crbug.com/293561 |
365 # | 453 # |
366 # Currently if distinguishing non-primitive type from primitive type, | 454 # Currently if distinguishing non-primitive type from primitive type, |
367 # (e.g., sequence<DOMString> from DOMString or Dictionary from double) | 455 # (e.g., sequence<DOMString> from DOMString or Dictionary from double) |
368 # the method with a non-primitive type argument must appear *first* in the | 456 # the method with a non-primitive type argument must appear *first* in the |
369 # IDL file, since we're not adding a check to primitive types. | 457 # IDL file, since we're not adding a check to primitive types. |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 deleter = next( | 825 deleter = next( |
738 method | 826 method |
739 for method in interface.operations | 827 for method in interface.operations |
740 if ('deleter' in method.specials and | 828 if ('deleter' in method.specials and |
741 len(method.arguments) == 1 and | 829 len(method.arguments) == 1 and |
742 str(method.arguments[0].idl_type) == 'DOMString')) | 830 str(method.arguments[0].idl_type) == 'DOMString')) |
743 except StopIteration: | 831 except StopIteration: |
744 return None | 832 return None |
745 | 833 |
746 return property_deleter(deleter) | 834 return property_deleter(deleter) |
OLD | NEW |