| 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 |