OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
3 # for details. All rights reserved. Use of this source code is governed by a | 3 # for details. All rights reserved. Use of this source code is governed by a |
4 # BSD-style license that can be found in the LICENSE file. | 4 # BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 """This module provides shared functionality for the systems to generate | 6 """This module provides shared functionality for the systems to generate |
7 wrapping binding from the IDL database.""" | 7 wrapping binding from the IDL database.""" |
8 | 8 |
| 9 import generator |
9 import os | 10 import os |
10 from generator import * | 11 from generator import * |
11 from systembase import * | 12 from systembase import * |
12 | 13 |
13 class WrappingImplementationSystem(System): | 14 class WrappingImplementationSystem(System): |
14 | 15 |
15 def __init__(self, templates, database, emitters, output_dir): | 16 def __init__(self, templates, database, emitters, output_dir): |
16 """Prepared for generating wrapping implementation. | 17 """Prepared for generating wrapping implementation. |
17 | 18 |
18 - Creates emitter for JS code. | 19 - Creates emitter for JS code. |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 ' }\n', | 366 ' }\n', |
366 TYPE=info.type_name, | 367 TYPE=info.type_name, |
367 NAME=info.name, | 368 NAME=info.name, |
368 PARAMS=info.ParametersImplementationDeclaration()) | 369 PARAMS=info.ParametersImplementationDeclaration()) |
369 | 370 |
370 # Process in order of ascending number of arguments to ensure missing | 371 # Process in order of ascending number of arguments to ensure missing |
371 # optional arguments are processed early. | 372 # optional arguments are processed early. |
372 overloads = sorted(info.overloads, | 373 overloads = sorted(info.overloads, |
373 key=lambda overload: len(overload.arguments)) | 374 key=lambda overload: len(overload.arguments)) |
374 self._native_version = 0 | 375 self._native_version = 0 |
375 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | 376 fallthrough = generator.GenerateDispatch(self, body, info, ' ', 0, overlo
ads) |
376 if fallthrough: | 377 if fallthrough: |
377 body.Emit(' throw "Incorrect number or type of arguments";\n'); | 378 body.Emit(' throw "Incorrect number or type of arguments";\n'); |
378 | 379 |
379 def AddStaticOperation(self, info): | 380 def AddStaticOperation(self, info): |
380 pass | 381 pass |
381 | 382 |
382 def GenerateSingleOperation(self, emitter, info, indent, operation): | 383 def GenerateSingleOperation(self, emitter, info, indent, operation): |
383 """Generates a call to a single operation. | 384 """Generates a call to a single operation. |
384 | 385 |
385 Arguments: | 386 Arguments: |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n' | 419 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n' |
419 '$(INDENT)return;\n', | 420 '$(INDENT)return;\n', |
420 INDENT=indent, | 421 INDENT=indent, |
421 NATIVENAME=native_name, | 422 NATIVENAME=native_name, |
422 ARGS=argument_expressions) | 423 ARGS=argument_expressions) |
423 | 424 |
424 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n', | 425 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n', |
425 NAME=native_name, | 426 NAME=native_name, |
426 TYPE=info.type_name, | 427 TYPE=info.type_name, |
427 PARAMS=', '.join(['receiver'] + arg_names) ) | 428 PARAMS=', '.join(['receiver'] + arg_names) ) |
428 | |
429 | |
430 def GenerateDispatch(self, emitter, info, indent, position, overloads): | |
431 """Generates a dispatch to one of the overloads. | |
432 | |
433 Arguments: | |
434 emitter: an Emitter for the body of a block of code. | |
435 info: the compound information about the operation and its overloads. | |
436 indent: an indentation string for generated code. | |
437 position: the index of the parameter to dispatch on. | |
438 overloads: a list of the remaining IDLOperations to dispatch. | |
439 | |
440 Returns True if the dispatch can fall through on failure, False if the code | |
441 always dispatches. | |
442 """ | |
443 | |
444 def NullCheck(name): | |
445 return '%s === null' % name | |
446 | |
447 def TypeCheck(name, type): | |
448 return '%s is %s' % (name, type) | |
449 | |
450 def ShouldGenerateSingleOperation(): | |
451 if position == len(info.param_infos): | |
452 if len(overloads) > 1: | |
453 raise Exception('Duplicate operations ' + str(overloads)) | |
454 return True | |
455 | |
456 # Check if we dispatch on RequiredCppParameter arguments. In this | |
457 # case all trailing arguments must be RequiredCppParameter and there | |
458 # is no need in dispatch. | |
459 # TODO(antonm): better diagnositics. | |
460 if position >= len(overloads[0].arguments): | |
461 def IsRequiredCppParameter(arg): | |
462 return 'RequiredCppParameter' in arg.ext_attrs | |
463 last_overload = overloads[-1] | |
464 if (len(last_overload.arguments) > position and | |
465 IsRequiredCppParameter(last_overload.arguments[position])): | |
466 for overload in overloads: | |
467 args = overload.arguments[position:] | |
468 if not all([IsRequiredCppParameter(arg) for arg in args]): | |
469 raise Exception('Invalid overload for RequiredCppParameter') | |
470 return True | |
471 | |
472 return False | |
473 | |
474 if ShouldGenerateSingleOperation(): | |
475 self.GenerateSingleOperation(emitter, info, indent, overloads[-1]) | |
476 return False | |
477 | |
478 # FIXME: Consider a simpler dispatch that iterates over the | |
479 # overloads and generates an overload specific check. Revisit | |
480 # when we move to named optional arguments. | |
481 | |
482 # Partition the overloads to divide and conquer on the dispatch. | |
483 positive = [] | |
484 negative = [] | |
485 first_overload = overloads[0] | |
486 param = info.param_infos[position] | |
487 | |
488 if position < len(first_overload.arguments): | |
489 # FIXME: This will not work if the second overload has a more | |
490 # precise type than the first. E.g., | |
491 # void foo(Node x); | |
492 # void foo(Element x); | |
493 type = DartType(first_overload.arguments[position].type.id) | |
494 test = TypeCheck(param.name, type) | |
495 pred = lambda op: len(op.arguments) > position and DartType(op.arguments[p
osition].type.id) == type | |
496 else: | |
497 type = None | |
498 test = NullCheck(param.name) | |
499 pred = lambda op: position >= len(op.arguments) | |
500 | |
501 for overload in overloads: | |
502 if pred(overload): | |
503 positive.append(overload) | |
504 else: | |
505 negative.append(overload) | |
506 | |
507 if positive and negative: | |
508 (true_code, false_code) = emitter.Emit( | |
509 '$(INDENT)if ($COND) {\n' | |
510 '$!TRUE' | |
511 '$(INDENT)} else {\n' | |
512 '$!FALSE' | |
513 '$(INDENT)}\n', | |
514 COND=test, INDENT=indent) | |
515 fallthrough1 = self.GenerateDispatch( | |
516 true_code, info, indent + ' ', position + 1, positive) | |
517 fallthrough2 = self.GenerateDispatch( | |
518 false_code, info, indent + ' ', position, negative) | |
519 return fallthrough1 or fallthrough2 | |
520 | |
521 if negative: | |
522 raise Exception('Internal error, must be all positive') | |
523 | |
524 # All overloads require the same test. Do we bother? | |
525 | |
526 # If the test is the same as the method's formal parameter then checked mode | |
527 # will have done the test already. (It could be null too but we ignore that | |
528 # case since all the overload behave the same and we don't know which types | |
529 # in the IDL are not nullable.) | |
530 if type == param.dart_type: | |
531 return self.GenerateDispatch( | |
532 emitter, info, indent, position + 1, positive) | |
533 | |
534 # Otherwise the overloads have the same type but the type is a subtype of | |
535 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
536 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
537 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
538 # that Y = Z-X, so we need to check for Y. | |
539 true_code = emitter.Emit( | |
540 '$(INDENT)if ($COND) {\n' | |
541 '$!TRUE' | |
542 '$(INDENT)}\n', | |
543 COND=test, INDENT=indent) | |
544 self.GenerateDispatch( | |
545 true_code, info, indent + ' ', position + 1, positive) | |
546 return True | |
OLD | NEW |